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.
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 │
└──────────────┴──────────────┴──────────────┴────────────┘
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
- Go to Firebase Console
- Click “Add project” and enter a project name (no spaces)
- Optionally enable Google Analytics
- Click “Create project”
- Wait for provisioning, then access the 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);
For iOS Apps:
- Download
GoogleService-Info.plistand add to your Xcode project.
For Android Apps:
- Download
google-services.jsonand place in theapp/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'
}
Step 3: Enable Authentication Methods
Go to Firebase Console > Authentication > Sign-in method:
- Email/Password: Enable for traditional sign-up.
- Google: Add SHA-1 fingerprint (Android) or bundle ID (iOS).
- Apple: Required for iOS apps with any social login.
- 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);
}
}
}
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');
}
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');
}
}
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';
}
});
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
}
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)
Initialize Firestore
import { getFirestore } from 'firebase/firestore';
const db = getFirestore(app);
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'
});
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);
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')
});
Delete Documents
import { deleteDoc } from 'firebase/firestore';
async function deleteUser(userId) {
await deleteDoc(doc(db, 'users', userId));
console.log('User deleted');
}
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();
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);
}
}
}
Query Limitations
Firestore constraints:
-
No OR queries (use
inwith arrays or multiple queries) - No wildcard searches (use Algolia/Meilisearch for full-text)
- Compound queries need indexes
-
Limit of 30 disjunctions in
inqueries
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
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
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' });
}
});
Deploy:
firebase deploy --only functions:getUserProfile
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;
}
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();
}
}
);
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`);
});
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);
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
}
}
}
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
});
}
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;
}
}
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');
}
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
- Open Apidog
- Create a new project: “Firebase API”
- 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 }
}
}
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
}
Test Authentication Flow
- Create request: “Sign In”
- Set method: POST
- Add email/password in body
- Save response token as environment variable
- 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
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;
}
}
}
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')
);
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
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)
});
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
}
});
Common Firebase API Issues and Solutions
Issue 1: Permission Denied Errors
Symptom: Error: 7 PERMISSION_DENIED
Cause: Security rules block the operation
Fix:
- Inspect rules in Firebase Console
- Verify
request.auth.uidmatches the authenticated user - 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
}
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');
});
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)