DEV Community

Cover image for How to Use Firebase API: Complete Integration Guide (2026)
Wanda
Wanda

Posted on • Originally published at apidog.com

How to Use Firebase API: Complete Integration Guide (2026)

You’re building an app. Users need to sign in. Data needs to sync in real time. Files need storage. Instead of spending weeks spinning up servers and configuring databases, you can use Firebase.

Try Apidog today

Firebase powers over 1.5 million apps—including The New York Times, Duolingo, and Alibaba—because it removes backend complexity. You focus on features, not server maintenance. However, the Firebase API has quirks: authentication flows can be confusing, database rules are tricky, and Cloud Functions require understanding trigger logic.

This guide distills practical integration lessons from building production apps with Firebase. Learn how to implement authentication, database operations, Cloud Functions, and storage—with code samples and actionable advice. Avoid common pitfalls that impact real-world deployments.

💡 Tip: Testing Firebase APIs is easier with the right API client tooling. Apidog lets you organize endpoints, test authentication flows, and share collections with your team. We’ll show where it fits naturally in the workflow.

What Is Firebase API and Why Does It Matter?

Firebase is a suite of backend services accessible via SDKs and REST endpoints.

Core Firebase Services

Service Purpose API Type
Authentication User sign-in and identity SDK + REST
Firestore Database NoSQL document database SDK + REST
Realtime Database JSON real-time sync SDK + REST
Cloud Storage File storage and CDN SDK + REST
Cloud Functions Serverless compute Deployment CLI
Hosting Static web hosting Deployment CLI
Cloud Messaging Push notifications HTTP v1 API

When Firebase Makes Sense

Use Firebase when:

  • You need real-time sync (chat, collaboration, live updates)
  • You want serverless architecture (no infrastructure to manage)
  • You’re building mobile/web apps (SDKs unify platforms)
  • You need offline support (SDK caching)
  • You want built-in authentication (Google, Apple, email, phone)

Skip Firebase when:

  • You need complex relational queries (use PostgreSQL etc.)
  • You have strict data residency needs (limited regions)
  • You require full SQL capabilities (Firestore has query limitations)
  • Cost at scale outweighs development speed (self-hosting may be cheaper)

The Firebase API Architecture

Firebase uses a hybrid approach:

┌─────────────────────────────────────────────────────────┐
│                    Your Application                      │
├─────────────────────────────────────────────────────────┤
│  Firebase SDK (Client)                                   │
│  - Auto-handles auth tokens                              │
│  - Manages offline cache                                 │
│  - Real-time listeners                                   │
└─────────────────────────────────────────────────────────┘
                          │
                          │ HTTPS + WebSocket
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   Firebase Backend                       │
├──────────────┬──────────────┬──────────────┬────────────┤
│   Auth       │  Firestore   │   Storage    │ Functions  │
│   Service    │  Database    │   Service    │  Runtime   │
└──────────────┴──────────────┴──────────────┴────────────┘
Enter fullscreen mode Exit fullscreen mode

Client SDKs abstract the HTTP layer. Every operation maps to REST API calls with JWT authentication.


Firebase Authentication: Complete Setup

Authentication is the first integration step. If it’s not set up correctly, nothing else works.

Step 1: Create Firebase Project

  1. Go to Firebase Console
  2. Click “Add project” and enter a project name (no spaces)

Firebase project step 1

  1. Optionally enable Google Analytics

Firebase project step 2

  1. Click “Create project”

Firebase project step 3

  1. Wait for provisioning, then access the project dashboard

Firebase project dashboard

Step 2: Register Your App

For Web Apps:

// In Firebase Console > Project Settings > General
// Click "Add app" > Web icon

const firebaseConfig = {
  apiKey: "AIzaSyDxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain: "your-app.firebaseapp.com",
  projectId: "your-app",
  storageBucket: "your-app.appspot.com",
  messagingSenderId: "123456789012",
  appId: "1:123456789012:web:abc123def456"
};

// Initialize Firebase
import { initializeApp } from 'firebase/app';
const app = initializeApp(firebaseConfig);
Enter fullscreen mode Exit fullscreen mode

For iOS Apps:

  • Download GoogleService-Info.plist and add to your Xcode project.

For Android Apps:

  • Download google-services.json and place in the app/ directory.
  • Add to build.gradle:
// Project-level build.gradle
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.4.0'
    }
}

// App-level build.gradle
plugins {
    id 'com.google.gms.google-services'
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Enable Authentication Methods

Go to Firebase Console > Authentication > Sign-in method:

  1. Email/Password: Enable for traditional sign-up.
  2. Google: Add SHA-1 fingerprint (Android) or bundle ID (iOS).
  3. Apple: Required for iOS apps with any social login.
  4. Phone: Enable for SMS authentication (requires billing).

Step 4: Implement Authentication Flow

Email/Password Sign-Up:

import {
  createUserWithEmailAndPassword,
  getAuth,
  updateProfile
} from 'firebase/auth';

const auth = getAuth(app);

async function signUp(email, password, displayName) {
  try {
    const userCredential = await createUserWithEmailAndPassword(
      auth,
      email,
      password
    );

    // Set display name
    await updateProfile(userCredential.user, {
      displayName: displayName
    });

    console.log('User created:', userCredential.user.uid);
    return userCredential.user;
  } catch (error) {
    switch (error.code) {
      case 'auth/email-already-in-use':
        throw new Error('This email is already registered');
      case 'auth/weak-password':
        throw new Error('Password must be at least 6 characters');
      case 'auth/invalid-email':
        throw new Error('Invalid email address');
      default:
        throw new Error('Sign up failed: ' + error.message);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Email/Password Sign-In:

import {
  signInWithEmailAndPassword,
  signOut
} from 'firebase/auth';

async function signIn(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(
      auth,
      email,
      password
    );

    const user = userCredential.user;
    const idToken = await user.getIdToken();
    console.log('Auth token:', idToken);

    return user;
  } catch (error) {
    switch (error.code) {
      case 'auth/user-not-found':
        throw new Error('No account with this email');
      case 'auth/wrong-password':
        throw new Error('Incorrect password');
      case 'auth/too-many-requests':
        throw new Error('Too many attempts. Try again later');
      default:
        throw new Error('Sign in failed');
    }
  }
}

async function logOut() {
  await signOut(auth);
  console.log('User signed out');
}
Enter fullscreen mode Exit fullscreen mode

Google Sign-In (Web):

import {
  GoogleAuthProvider,
  signInWithPopup
} from 'firebase/auth';

async function signInWithGoogle() {
  const provider = new GoogleAuthProvider();
  provider.addScope('email');
  provider.addScope('profile');

  try {
    const result = await signInWithPopup(auth, provider);
    const user = result.user;
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const googleAccessToken = credential.accessToken;
    return user;
  } catch (error) {
    if (error.code === 'auth/popup-closed-by-user') {
      throw new Error('Sign-in cancelled');
    }
    throw new Error('Google sign-in failed');
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Protect Routes with Auth State

import { onAuthStateChanged } from 'firebase/auth';

onAuthStateChanged(auth, (user) => {
  if (user) {
    console.log('User:', user.email);
    window.location.href = '/dashboard';
  } else {
    console.log('No user');
    window.location.href = '/login';
  }
});
Enter fullscreen mode Exit fullscreen mode

Common Authentication Mistakes

Mistake 1: Not handling token refresh

  • Firebase SDK refreshes tokens, but server-side cached tokens expire after 1 hour. Always verify tokens per request or refresh them.

Mistake 2: Exposing admin credentials in client code

  • Never include service account keys in client apps. Use them only in secure server environments.

Mistake 3: Skipping email verification

import { sendEmailVerification } from 'firebase/auth';

async function sendVerificationEmail(user) {
  await sendEmailVerification(user);
  console.log('Verification email sent');
}

// Check verification status
if (!auth.currentUser.emailVerified) {
  console.log('Email not verified');
  // Restrict access
}
Enter fullscreen mode Exit fullscreen mode

Firestore Database: Operations and Queries

Firestore is a NoSQL document database. Documents are organized in collections and queries scale automatically.

Data Structure

your-project (root)
└── users (collection)
    ├── userId123 (document)
    │   ├── name: "John"
    │   ├── email: "john@example.com"
    │   └── posts (subcollection)
    │       ├── postId1 (document)
    │       └── postId2 (document)
    └── userId456 (document)
Enter fullscreen mode Exit fullscreen mode

Initialize Firestore

import { getFirestore } from 'firebase/firestore';

const db = getFirestore(app);
Enter fullscreen mode Exit fullscreen mode

Create Documents

import {
  collection,
  addDoc,
  setDoc,
  doc
} from 'firebase/firestore';

// Auto-generated ID
async function createUser(userData) {
  const docRef = await addDoc(collection(db, 'users'), userData);
  console.log('Document written with ID:', docRef.id);
  return docRef.id;
}

// Custom ID
async function createUserWithId(userId, userData) {
  await setDoc(doc(db, 'users', userId), userData);
  console.log('Document written with custom ID:', userId);
}

// Usage
const userId = await createUser({
  name: 'Alice',
  email: 'alice@example.com',
  createdAt: new Date(),
  role: 'user'
});
Enter fullscreen mode Exit fullscreen mode

Read Documents

import {
  getDoc,
  getDocs,
  query,
  where,
  orderBy,
  limit
} from 'firebase/firestore';

// Get single document
async function getUser(userId) {
  const docRef = doc(db, 'users', userId);
  const docSnap = await getDoc(docRef);

  if (docSnap.exists()) {
    return docSnap.data();
  } else {
    throw new Error('User not found');
  }
}

// Query with filters
async function getUsersByRole(role) {
  const q = query(
    collection(db, 'users'),
    where('role', '==', role),
    orderBy('createdAt', 'desc'),
    limit(10)
  );

  const querySnapshot = await getDocs(q);
  const users = [];

  querySnapshot.forEach((doc) => {
    users.push({ id: doc.id, ...doc.data() });
  });

  return users;
}

// Usage
const adminUsers = await getUsersByRole('admin');
console.log('Admin users:', adminUsers);
Enter fullscreen mode Exit fullscreen mode

Update Documents

import {
  updateDoc,
  increment,
  arrayUnion,
  arrayRemove
} from 'firebase/firestore';

async function updateUser(userId, updates) {
  const userRef = doc(db, 'users', userId);
  await updateDoc(userRef, updates);
}

// Atomic operations
await updateUser('userId123', {
  loginCount: increment(1),
  tags: arrayUnion('premium', 'beta-tester'),
  lastLogin: new Date()
});

// Remove from array
await updateUser('userId123', {
  tags: arrayRemove('beta-tester')
});
Enter fullscreen mode Exit fullscreen mode

Delete Documents

import { deleteDoc } from 'firebase/firestore';

async function deleteUser(userId) {
  await deleteDoc(doc(db, 'users', userId));
  console.log('User deleted');
}
Enter fullscreen mode Exit fullscreen mode

Real-Time Listeners

import { onSnapshot } from 'firebase/firestore';

// Listen to single document
const unsubscribe = onSnapshot(
  doc(db, 'users', userId),
  (doc) => {
    console.log('User updated:', doc.data());
  },
  (error) => {
    console.error('Listen error:', error);
  }
);

// Listen to query results
const q = query(collection(db, 'posts'), where('published', '==', true));

const unsubscribeQuery = onSnapshot(q, (snapshot) => {
  const posts = snapshot.docs.map(doc => ({
    id: doc.id,
    ...doc.data()
  }));
  console.log('Published posts:', posts);
});

// Stop listening
unsubscribe();
unsubscribeQuery();
Enter fullscreen mode Exit fullscreen mode

Firestore Security Rules

Set rules in Firebase Console > Firestore > Rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    function isAuthenticated() {
      return request.auth != null;
    }

    function isOwner(userId) {
      return request.auth.uid == userId;
    }

    match /users/{userId} {
      allow read: if isAuthenticated();
      allow create: if isAuthenticated() && isOwner(userId);
      allow update, delete: if isOwner(userId);
    }

    match /posts/{postId} {
      allow read: if true; // Public read
      allow create: if isAuthenticated();
      allow update, delete: if resource.data.authorId == request.auth.uid;
    }

    match /users/{userId}/private/{document} {
      allow read, write: if isOwner(userId);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Query Limitations

Firestore constraints:

  • No OR queries (use in with arrays or multiple queries)
  • No wildcard searches (use Algolia/Meilisearch for full-text)
  • Compound queries need indexes
  • Limit of 30 disjunctions in in queries

Workaround for OR queries:

// Instead of: where('status', '==', 'active') OR where('status', '==', 'pending')
const activeQuery = query(
  collection(db, 'tasks'),
  where('status', '==', 'active')
);

const pendingQuery = query(
  collection(db, 'tasks'),
  where('status', '==', 'pending')
);

const [activeSnap, pendingSnap] = await Promise.all([
  getDocs(activeQuery),
  getDocs(pendingQuery)
]);

// Merge results client-side
Enter fullscreen mode Exit fullscreen mode

Cloud Functions: Serverless Backend Logic

Cloud Functions let you run backend code on database changes, HTTP requests, or schedules. No server management required.

Setup

# Install Firebase CLI
npm install -g firebase-tools

# Login
firebase login

# Initialize functions in your project
firebase init functions

# Choose JavaScript, ESLint yes, Express.js no
Enter fullscreen mode Exit fullscreen mode

HTTP Functions (API Endpoints)

// functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const admin = require('firebase-admin');

admin.initializeApp();
const db = admin.firestore();

// Public endpoint
exports.getPublicData = onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  try {
    const snapshot = await db.collection('public').get();
    const data = snapshot.docs.map(doc => doc.data());
    res.json({ success: true, data });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Protected endpoint (verify auth token)
exports.getUserProfile = onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  const authHeader = req.headers.authorization || '';
  const token = authHeader.split('Bearer ')[1];

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  try {
    const decodedToken = await admin.auth().verifyIdToken(token);
    const userId = decodedToken.uid;
    const userDoc = await db.collection('users').doc(userId).get();

    if (!userDoc.exists) {
      return res.status(404).json({ error: 'User not found' });
    }

    res.json({
      success: true,
      data: { id: userId, ...userDoc.data() }
    });
  } catch (error) {
    res.status(401).json({ error: 'Invalid token' });
  }
});
Enter fullscreen mode Exit fullscreen mode

Deploy:

firebase deploy --only functions:getUserProfile
Enter fullscreen mode Exit fullscreen mode

Call from client:

async function getUserProfile(token) {
  const response = await fetch(
    'https://us-central1-your-app.cloudfunctions.net/getUserProfile',
    {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    }
  );
  const data = await response.json();
  return data;
}
Enter fullscreen mode Exit fullscreen mode

Database Triggers

const { onDocumentWritten } = require('firebase-functions/v2/firestore');

// Trigger when user document changes
exports.onUserUpdate = onDocumentWritten(
  'users/{userId}',
  async (event) => {
    const userId = event.params.userId;
    const before = event.data?.before?.data();
    const after = event.data?.after?.data();

    if (before?.email !== after?.email) {
      console.log(`User ${userId} email changed: ${before?.email}${after?.email}`);
      await admin.auth().getUser(userId);
      // Add notification logic here
    }
  }
);

// Trigger on new post creation
exports.onNewPost = onDocumentWritten(
  'posts/{postId}',
  async (event) => {
    const post = event.data?.after?.data();
    if (!post) return; // Document deleted

    if (!event.data?.before?.exists) {
      console.log('New post created:', post.title);
      const followersSnap = await admin.firestore()
        .collection('users')
        .where('following', 'array-contains', post.authorId)
        .get();

      const notifications = followersSnap.docs.map(doc => ({
        userId: doc.id,
        postId: event.params.postId,
        type: 'new_post',
        createdAt: admin.firestore.FieldValue.serverTimestamp()
      }));

      const batch = admin.firestore().batch();
      notifications.forEach(notif => {
        const ref = admin.firestore().collection('notifications').doc();
        batch.set(ref, notif);
      });

      await batch.commit();
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Scheduled Functions (Cron Jobs)

const { onSchedule } = require('firebase-functions/v2/scheduler');

// Run every day at midnight UTC
exports.dailyCleanup = onSchedule('every 24 hours', async (event) => {
  console.log('Running daily cleanup');
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const oldNotifs = await admin.firestore()
    .collection('notifications')
    .where('createdAt', '<', thirtyDaysAgo)
    .get();

  const batch = admin.firestore().batch();
  oldNotifs.forEach(doc => batch.delete(doc.ref));
  await batch.commit();

  console.log(`Deleted ${oldNotifs.size} old notifications`);
});
Enter fullscreen mode Exit fullscreen mode

Environment Configuration

# Set environment variables
firebase functions:config:set \
  stripe.secret="sk_test_xxx" \
  email.api_key="key_xxx"

# Access in functions
const config = require('firebase-functions/config');
const stripe = require('stripe')(config.stripe.secret);
Enter fullscreen mode Exit fullscreen mode

Cloud Storage: File Upload and Management

Store user uploads, images, and files with automatic CDN delivery.

Setup Storage Rules

// Firebase Console > Storage > Rules
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {

    match /users/{userId}/{allPaths=**} {
      allow read: if true; // Public read
      allow write: if request.auth.uid == userId;
      allow delete: if request.auth.uid == userId;
    }

    match /public/{allPaths=**} {
      allow read: if true;
      allow write: if false; // Admin only via Firebase Console
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Upload Files (Client)

import {
  getStorage,
  ref,
  uploadBytesResumable,
  getDownloadURL
} from 'firebase/storage';

const storage = getStorage(app);

async function uploadProfileImage(userId, file) {
  const storageRef = ref(storage, `users/${userId}/profile/${file.name}`);
  const uploadTask = uploadBytesResumable(storageRef, file);

  return new Promise((resolve, reject) => {
    uploadTask.on(
      'state_changed',
      (snapshot) => {
        const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        console.log(`Upload: ${progress.toFixed(0)}%`);
      },
      (error) => {
        switch (error.code) {
          case 'storage/unauthorized':
            reject(new Error('You do not have permission'));
            break;
          case 'storage/canceled':
            reject(new Error('Upload cancelled'));
            break;
          default:
            reject(new Error('Upload failed'));
        }
      },
      async () => {
        const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
        console.log('File available at:', downloadURL);
        resolve(downloadURL);
      }
    );
  });
}

// Usage
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

if (file) {
  const imageUrl = await uploadProfileImage(auth.currentUser.uid, file);

  // Save URL to Firestore
  await updateDoc(doc(db, 'users', auth.currentUser.uid), {
    profileImage: imageUrl
  });
}
Enter fullscreen mode Exit fullscreen mode

Download Files

import { getDownloadURL } from 'firebase/storage';

async function getProfileImage(userId) {
  const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
  try {
    const url = await getDownloadURL(imageRef);
    return url;
  } catch (error) {
    if (error.code === 'storage/object-not-found') {
      return null;
    }
    throw error;
  }
}
Enter fullscreen mode Exit fullscreen mode

Delete Files

import { deleteObject } from 'firebase/storage';

async function deleteProfileImage(userId) {
  const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
  await deleteObject(imageRef);
  console.log('Profile image deleted');
}
Enter fullscreen mode Exit fullscreen mode

Testing Firebase APIs with Apidog

Firebase exposes REST APIs for all services. Directly testing these is crucial for debugging and understanding request flows.

Import Firebase REST API

  1. Open Apidog
  2. Create a new project: “Firebase API”
  3. Import OpenAPI spec from Firebase docs or add endpoints manually.

Firestore REST Endpoint:

POST https://firestore.googleapis.com/v1/projects/{projectId}/databases/(default)/documents
Authorization: Bearer {oauth2_token}
Content-Type: application/json

{
  "fields": {
    "name": { "stringValue": "John" },
    "email": { "stringValue": "john@example.com" },
    "age": { "integerValue": 30 }
  }
}
Enter fullscreen mode Exit fullscreen mode

Authentication Endpoint:

POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={api_key}
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secret123",
  "returnSecureToken": true
}
Enter fullscreen mode Exit fullscreen mode

Test Authentication Flow

  1. Create request: “Sign In”
  2. Set method: POST
  3. Add email/password in body
  4. Save response token as environment variable
  5. Use {{token}} in subsequent requests

Debug Security Rules

Use Firebase Emulator Suite for local testing:

# Start emulator
firebase emulators:start

# Test against local Firestore
# http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Production Best Practices

1. Implement Proper Error Handling

// Retry logic for transient failures
async function firestoreWithRetry(operation, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation();
    } catch (error) {
      if (
        error.code === 'unavailable' ||
        error.code === 'deadline-exceeded'
      ) {
        const delay = Math.pow(2, i) * 1000;
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Optimize Query Performance

Add composite indexes for multi-field queries:

// This query needs a composite index
const q = query(
  collection(db, 'posts'),
  where('category', '==', 'tech'),
  where('views', '>', 1000),
  orderBy('views', 'desc')
);
Enter fullscreen mode Exit fullscreen mode

Firestore will prompt to create the index with a direct link.

3. Batch Operations

import { writeBatch } from 'firebase/firestore';

async function bulkUpdate(userIds, updates) {
  const batch = writeBatch(db);
  userIds.forEach(id => {
    const ref = doc(db, 'users', id);
    batch.update(ref, updates);
  });
  await batch.commit();
  console.log(`Updated ${userIds.length} users`);
}
// Max 500 operations per batch
Enter fullscreen mode Exit fullscreen mode

4. Monitor Costs

Firebase pricing:

Service Free Tier Paid
Firestore 50K reads/day $0.036/100K reads
Storage 5GB $0.023/GB
Functions 2M invocations $0.40/1M
Auth 10K/month $0.0055/100K

Set budget alerts in Google Cloud Console.

5. Secure Service Accounts

// WRONG: Never do this in client code
admin.initializeApp({
  credential: admin.credential.cert(require('./serviceAccountKey.json'))
});

// CORRECT: Use in server environment only
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});
Enter fullscreen mode Exit fullscreen mode

6. Handle Offline Scenarios

// Enable offline persistence (web)
import { enableMultiTabIndexedDbPersistence } from 'firebase/firestore';

enableMultiTabIndexedDbPersistence(db)
  .catch((err) => {
    if (err.code === 'failed-precondition') {
      // Multiple tabs open
    } else if (err.code === 'unimplemented') {
      // Browser doesn't support
    }
  });

// Listen to connectivity
import { onSnapshot } from 'firebase/firestore';

onSnapshot(doc(db, 'status', 'online'), (doc) => {
  if (!doc.exists()) {
    console.log('You are offline');
    // Show offline UI
  }
});
Enter fullscreen mode Exit fullscreen mode

Common Firebase API Issues and Solutions

Issue 1: Permission Denied Errors

Symptom: Error: 7 PERMISSION_DENIED

Cause: Security rules block the operation

Fix:

  1. Inspect rules in Firebase Console
  2. Verify request.auth.uid matches the authenticated user
  3. Use Rules Playground for testing

Issue 2: Token Expiration

Symptom: Error: ID token expired

Fix:

// Force token refresh
const user = auth.currentUser;
if (user) {
  await user.getIdToken(true); // Force refresh
}
Enter fullscreen mode Exit fullscreen mode

Issue 3: Cold Start Latency

Symptom: Cloud Functions are slow on first call

Fix:

// Keep functions warm with scheduled pings
exports.keepWarm = onSchedule('every 60 seconds', async () => {
  await fetch('https://your-function.cloudfunctions.net/health');
});
Enter fullscreen mode Exit fullscreen mode

Issue 4: Query Returns Empty Results

Symptom: Query returns empty array

Cause: Missing index or incorrect field order

Fix: Review Firestore Console > Indexes for required composite indexes.


Real-World Use Cases

Fintech App: Real-Time Transaction Updates

A payment startup uses Firestore for real-time transaction notifications. Cloud Functions trigger dashboard updates within 200ms after a payment, reducing support tickets about “pending” transactions by 40%.

E-commerce: Inventory Synchronization

An online retailer syncs inventory across web, iOS, and Android using Firestore listeners. Stock changes update all clients automatically. Offline persistence allows warehouse workers to scan items without connectivity and syncs when reconnected.

SaaS: Multi-Tenant Authentication

A B2B platform implements Firebase Auth with custom claims for role-based access. Cloud Functions validate permissions against Firestore tenant configs. A single codebase serves 500+ organizations with isolated data.


Conclusion

Firebase API integration revolves around four core services:

  • Authentication: Email, Google, Apple sign-in with JWT tokens
  • Firestore: NoSQL database with real-time listeners and security rules
  • Cloud Functions: Serverless backend logic (event- and HTTP-triggered)
  • Storage: File uploads with CDN distribution

You now have actionable patterns for authentication flows, database operations, function deployment, and file management—plus best practices for production error handling, batching, offline support, and security.


FAQ

Is Firebase free to use?

Yes, Firebase offers a generous free tier (Spark Plan) with 5GB storage, 50K Firestore reads/day, 2M Cloud Function invocations, and 10K Auth users/month. Paid plans (Blaze) use pay-as-you-go pricing.

Can I use Firebase with existing databases?

Yes. Use Firebase Extensions to sync with PostgreSQL, MySQL, or MongoDB. Or call external APIs from Cloud Functions to integrate with legacy systems.

How do I migrate from Firebase to another platform?

Export data using Firestore export functions or the Firebase CLI. For large datasets, use the Dataflow export pipeline. Migration complexity depends on your data model.

Does Firebase support GraphQL?

Not natively. Use third-party solutions like firestore-graphql or build a GraphQL layer with Cloud Functions and Apollo Server.

Can I use Firebase on-premise?

No. Firebase is Google Cloud-only. For self-hosted alternatives, consider Appwrite, Supabase, or Nhost.

How do I handle file uploads larger than 100MB?

Use resumable uploads with chunking (the Firebase SDK handles this automatically). For very large files, use Google Cloud Storage directly with signed URLs.

What happens if I exceed Firestore query limits?

Queries fail with FAILED_PRECONDITION errors. Add required indexes or restructure queries. Firestore provides direct links to create missing indexes in error messages.

Is Firebase GDPR compliant?

Yes, Firebase offers GDPR-compliant data processing. Enable data residency in specific regions, implement user data export/deletion, and sign Google’s Data Processing Amendment.

Top comments (0)