Top 47 Firebase / Firestore Interview Questions & Answers (2026)
About Firebase / Firestore
Top 50 Firebase and Firestore interview questions covering real-time database, authentication, Cloud Functions, security rules, and data modeling. Companies hiring for Firebase / Firestore roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.
What to Expect in a Firebase / Firestore Interview
Expect a mix of conceptual and practical Firebase / Firestore questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.
How to Use This Guide
Work through the Firebase / Firestore questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.
Curated by Tech Baithak Editorial Team · Last updated: June 2026
Core concepts every Firebase / Firestore developer must know.
01
What is Firebase?
Firebase is Google's comprehensive app development platform that provides a suite of cloud-based tools and services for building web and mobile applications. Launched in 2011 and acquired by Google in 2014, Firebase offers: Firestore (NoSQL document database), Realtime Database (JSON tree database), Authentication (user identity management), Cloud Storage (file storage), Cloud Functions (serverless backend), Firebase Hosting (static and dynamic web hosting), Cloud Messaging (push notifications), Analytics, Remote Config, App Check, and more. Firebase is designed to minimize backend development effort — its SDKs enable direct client-to-database communication with security rules, eliminating the need for a traditional REST API for many use cases. It is particularly popular for startups, mobile apps, and rapid prototyping.
02
What is Firestore?
Cloud Firestore (commonly called Firestore) is Google's flexible, scalable NoSQL document database built for mobile, web, and server development. It stores data as documents organized into collections. Key features: (1) Real-time sync — clients subscribe to data and receive updates in real time as data changes; (2) Offline support — local data caching allows apps to work offline and sync when reconnected; (3) Scalable — scales automatically from developer projects to planet-scale applications; (4) Flexible queries — supports compound queries, ordering, and filtering; (5) ACID transactions — atomic, consistent, isolated, durable operations; (6) Multi-region availability — global distribution with strong consistency guarantees. Firestore replaced the original Firebase Realtime Database as the recommended database for new projects, offering more powerful querying capabilities and better scalability.
03
What is the difference between Firebase Realtime Database and Firestore?
Both are Firebase databases but differ significantly: (1) Data model — Realtime Database stores data as one large JSON tree; Firestore stores data as collections of documents (more structured); (2) Querying — Realtime Database has limited querying (single field sorting/filtering); Firestore supports compound queries, multiple conditions, multiple field ordering; (3) Scalability — Realtime Database has write limits (~1000 ops/sec per database); Firestore scales automatically to millions of concurrent users; (4) Offline — both support offline; Firestore has better mobile offline support; (5) Pricing — Realtime Database: priced per GB stored and downloaded; Firestore: priced per operation count (reads/writes/deletes); (6) Regions — Realtime Database: single region; Firestore: multi-region and single-region options; (7) Security Rules — Firestore rules are more expressive and granular. Choose Firestore for new projects. Use Realtime Database only for low-latency sync or legacy apps.
04
What is Firebase Authentication?
Firebase Authentication is a managed identity service that handles user sign-up, sign-in, and identity management. It supports multiple authentication providers: Email/Password, Google, Facebook, Twitter, GitHub, Apple, Microsoft, Phone (SMS OTP), Anonymous, and Custom Tokens (SAML/OIDC for enterprise SSO). Key features: (1) Firebase Auth handles session management — issues JWTs automatically; (2) Integration with Firestore security rules — request.auth.uid enables user-specific data access; (3) Multi-factor authentication (MFA) — supports TOTP and SMS-based MFA; (4) Email verification and password reset — built-in flows; (5) Auth state persistence — user sessions persist across app restarts. Firebase Auth eliminates the need to build and maintain a custom authentication system, reducing development time significantly.
05
What is Firebase Hosting?
Firebase Hosting is a production-grade web hosting service for static assets (HTML, CSS, JavaScript, images) and dynamic content via Cloud Functions or Cloud Run. Key features: (1) Global CDN — content served from Fastly's global CDN with SSL by default; (2) One-command deploy — firebase deploy uploads and deploys in seconds; (3) Preview channels — firebase hosting:channel:deploy preview creates temporary preview URLs for testing before production; (4) Multiple sites — host multiple websites from one Firebase project; (5) Custom domains — configure custom domains with automatic SSL certificate provisioning; (6) Version history — easily roll back to previous deployments; (7) Framework integrations — official support for Next.js, Angular, Nuxt, and other frameworks via the firebase-frameworks experiment. Hosting is ideal for SPAs (React, Vue, Angular), static sites, and full-stack apps with Firebase backend services.
06
What is Firebase Cloud Functions?
Firebase Cloud Functions is a serverless framework that lets you run Node.js (or Python, in 2nd gen) backend code in response to Firebase events and HTTPS requests. Functions run in Google Cloud's managed environment — no server provisioning required. Trigger types: (1) HTTPS — function exposed as an HTTP endpoint; (2) Firestore triggers — run on document create, update, delete, or write; (3) Authentication triggers — run when a user creates or deletes an account; (4) Storage triggers — run when a file is uploaded, updated, or deleted; (5) Pub/Sub — run on message publication; (6) Scheduled — run on a CRON schedule; (7) Realtime Database triggers — run on data write. Firebase Cloud Functions extend Firebase's client-first architecture with server-side logic: sending emails after user creation, generating thumbnails after image upload, running business logic that shouldn't run on clients.
07
What is Firebase Cloud Messaging (FCM)?
Firebase Cloud Messaging (FCM) is Google's free, reliable messaging service for sending push notifications to Android, iOS, and web applications. It replaced Google Cloud Messaging (GCM) in 2016. FCM sends two types of messages: (1) Notification messages — displayed in the system notification tray automatically (no app code needed); (2) Data messages — delivered to the app code for custom handling. FCM features: Topic messaging — broadcast to all devices subscribed to a topic (e.g., "sports-news"); Device group messaging — send to all devices owned by a user; Downstream messaging — from your server to devices; Analytics integration — track notification open rates. Use cases: order updates, social notifications, breaking news alerts, reminders. FCM is free with no per-message cost, making it practical for high-volume notification systems. The Firebase Admin SDK enables server-side notification sending from Node.js, Java, Python, Go, and C#.
08
What is Firebase Analytics?
Firebase Analytics (now called Google Analytics for Firebase) is a free, unlimited analytics solution built into Firebase for mobile and web apps. It automatically logs 25+ predefined events (app_open, session_start, first_open, user_engagement, screen_view) and custom events you define. Key features: (1) User properties — define attributes for user segments (age, location, subscription tier); (2) Funnel analysis — visualize conversion paths through your app; (3) Cohort analysis — track user behavior over time; (4) Audience targeting — use Analytics audiences to target Firebase Remote Config, In-App Messaging, and FCM campaigns; (5) BigQuery integration — export raw event data to BigQuery for custom analysis; (6) Attribution — tracks which marketing campaigns drive installs and conversions; (7) Crash reporting integration — Crashlytics correlates crashes with user cohorts. Analytics data informs product decisions, marketing spend, and feature prioritization.
09
What is Firebase Storage?
Firebase Cloud Storage is Google Cloud Storage integration optimized for Firebase apps. It stores user-generated content — images, videos, audio files, documents — and provides client-side SDKs for uploading and downloading directly from the browser or mobile app. Key features: (1) Security Rules — Firebase Storage Security Rules control read/write access based on authentication state and custom conditions; (2) Resumable uploads — large file uploads automatically resume if interrupted; (3) Download URLs — generate temporary or permanent download URLs for files; (4) Progress monitoring — upload/download progress events for progress bars; (5) Multiple buckets — use different storage buckets for different data types or regions; (6) CDN integration — files are served via Google's global CDN. Common use cases: user profile pictures, document storage, media uploads. Cloud Functions can trigger on file upload to resize images, extract metadata, or perform virus scanning.
10
How do you add Firebase to a web app?
Adding Firebase to a web app involves these steps: (1) Create project — go to the Firebase Console (console.firebase.google.com), create a project, and add a web app to get the config object; (2) Install SDK — npm install firebase; (3) Initialize — import and initialize with your config: import { initializeApp } from "firebase/app"; const app = initializeApp({ apiKey: "...", authDomain: "...", projectId: "...", ... }); (4) Import services — import only the services you need (tree-shaking): import { getFirestore } from "firebase/firestore"; import { getAuth } from "firebase/auth"; (5) Use services — const db = getFirestore(app); const auth = getAuth(app). Firebase SDK v9+ uses a modular API that supports tree-shaking, significantly reducing bundle size. Use the Firebase Emulator Suite for local development to avoid affecting production data.
11
What is a Firestore collection?
A Firestore collection is a container for documents — similar to a table in a relational database or a MongoDB collection. Collections have these characteristics: (1) Identified by a path — e.g., /users, /posts; (2) Cannot hold raw data — only documents; (3) Schema-flexible — documents within a collection can have different fields; (4) Auto-created — collections are created implicitly when you create the first document in them; (5) Auto-deleted — collections disappear when all their documents are deleted (they are virtual containers). You reference a collection with collection(db, "users") in the Firebase SDK. Collections can only be created at the root level (top-level collections) or as subcollections inside documents. Subcollections enable hierarchical data organization: /users/{userId}/posts/{postId}.
12
What is a Firestore document?
A Firestore document is a unit of storage containing a set of key-value pairs (fields). Documents are analogous to rows in SQL or objects in JSON. Key characteristics: (1) Identified by an ID — either auto-generated by Firestore or specified by you; full path: /users/user123; (2) Size limit — maximum 1MB per document; (3) Fields — can contain: strings, numbers, booleans, null, timestamps, geopoints, arrays, maps (nested objects), and references to other documents; (4) Subcollections — documents can contain subcollections (nested collections), enabling hierarchical data; (5) Snapshots — when you read a document, you get a DocumentSnapshot containing the data and metadata. Creating: setDoc(doc(db, "users", "user123"), { name: "Alice", age: 30 }). Reading: const snap = await getDoc(doc(db, "users", "user123")); snap.data().
13
What are Firestore subcollections?
Subcollections are collections nested inside documents, enabling hierarchical data structures. A document can have any number of subcollections, each with their own documents, and those documents can have their own subcollections (up to 100 levels deep). Example: /users/{userId}/orders/{orderId} — each user document has an orders subcollection. Benefits: (1) Logical grouping — orders are naturally associated with their user; (2) Query isolation — you can query all orders for a specific user efficiently; (3) No size impact — subcollection data doesn't affect the parent document's 1MB limit; (4) Security — subcollection access can be controlled independently of the parent. Caution: you cannot query across subcollections with a standard collection query. If you need to query all orders across all users, use a top-level collection instead of subcollections. Collection Group Queries (introduced 2019) allow querying all subcollections with the same name across all documents.
14
What data types does Firestore support?
Firestore supports the following data types: (1) String — UTF-8 encoded text; (2) Integer — 64-bit signed integer; (3) Floating point — 64-bit IEEE 754 double-precision; (4) Boolean — true or false; (5) Timestamp — date and time (Firestore Timestamp object, not JavaScript Date); (6) Null; (7) Bytes — raw binary data (up to 1MB); (8) Geopoint — latitude/longitude pair; (9) Document Reference — a pointer to another Firestore document; (10) Array — ordered list of values; (11) Map — key-value pairs (nested objects). Arrays in Firestore have limitations: you can't query for documents where an array contains a specific value using standard queries without array-contains operator; arrays can't have array elements. Maps enable nested data structures. Firestore sorts data by type in a specific order for ordering queries: null, boolean, number, timestamp, string, bytes, reference, geopoint, array, map.
15
How do you read data from Firestore?
Reading Firestore data uses two approaches: (1) One-time fetch — getDoc() for a single document: const snap = await getDoc(doc(db, "users", "alice")); if (snap.exists()) { console.log(snap.data()) }. getDocs() for a collection: const q = query(collection(db, "posts"), orderBy("createdAt")); const snaps = await getDocs(q); snaps.forEach(doc => console.log(doc.id, doc.data())); (2) Real-time listener — onSnapshot() subscribes to changes: const unsub = onSnapshot(doc(db, "users", "alice"), snap => { console.log(snap.data()) }). The callback fires immediately with current data and again whenever the document changes. unsub() stops listening. Real-time listeners are the core of Firestore's real-time capabilities — use them when the UI must reflect live data. Prefer one-time fetches for data that only needs to be loaded once (profile pages, settings).
16
How do you write data to Firestore?
Firestore provides three write methods: (1) setDoc() — creates or completely overwrites a document: await setDoc(doc(db, "users", "alice"), { name: "Alice", email: "alice@example.com" }). Specify { merge: true } to merge instead of overwrite; (2) addDoc() — creates a document with auto-generated ID: const ref = await addDoc(collection(db, "posts"), { title: "Hello", author: "alice" }); console.log(ref.id); (3) updateDoc() — updates specific fields without overwriting the entire document: await updateDoc(doc(db, "users", "alice"), { lastSeen: serverTimestamp() }). If the document doesn't exist, updateDoc fails (use setDoc with merge for upsert behavior). Use serverTimestamp() for timestamps to avoid client-side clock skew. Field paths with dots ("address.city") update nested map fields without overwriting sibling fields.
17
How do you update data in Firestore?
Firestore provides several update approaches: (1) updateDoc() — updates only specified fields: await updateDoc(docRef, { score: increment(10), lastUpdated: serverTimestamp() }); (2) Dot notation for nested fields — update nested map fields without overwriting the whole map: updateDoc(ref, { "address.city": "New York" }) changes only the city; (3) Special field values — increment(n) atomically adds to a number (safe for counters), arrayUnion(value) adds to an array without duplicates, arrayRemove(value) removes from array, deleteField() removes a field, serverTimestamp() sets server-side timestamp; (4) setDoc() with merge — setDoc(ref, data, { merge: true }) creates the document if it doesn't exist, or merges fields if it does — useful for upsert patterns; (5) Transactions — use runTransaction() for conditional updates that read then write atomically.
18
How do you delete data in Firestore?
Deleting data in Firestore: (1) Delete a document — await deleteDoc(doc(db, "users", "alice")). Note: deleting a document does NOT delete its subcollections; they become orphaned but accessible via their direct path; (2) Delete a field — await updateDoc(ref, { fieldToDelete: deleteField() }). The deleteField() sentinel marks the field for removal; (3) Delete a collection — Firestore has no built-in operation to delete entire collections. You must query all documents and delete them in batches. For large collections, use the Firebase Admin SDK with a server-side script or Cloud Functions; (4) Delete array element — await updateDoc(ref, { tags: arrayRemove("oldTag") }); (5) Batch delete — use writeBatch() to delete multiple documents atomically (max 500 operations per batch). Important: never delete large collections from the client — use server-side batch deletion with pagination to handle collections of any size.
19
What are Firestore security rules?
Firestore Security Rules are a declarative language for defining access controls on your Firestore database. They run server-side and prevent unauthorized reads/writes. Rules are defined in the Firebase console or a firestore.rules file. Structure: rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read: if request.auth != null; allow write: if request.auth.uid == userId; } } }. Key concepts: (1) request.auth — contains the authenticated user's UID, email, and custom claims; (2) resource.data — the current document data; (3) request.resource.data — the incoming data being written; (4) Match rules — patterns with wildcards match paths; (5) Allow operations — read (get + list), write (create + update + delete), or granular: get, list, create, update, delete. Rules default to deny all — you must explicitly grant access.
20
What is Firebase SDK initialization?
Firebase SDK initialization configures your app to connect to your Firebase project. In Firebase SDK v9 (modular API): import { initializeApp } from "firebase/app"; const firebaseConfig = { apiKey: "your-api-key", authDomain: "project.firebaseapp.com", projectId: "project-id", storageBucket: "project.appspot.com", messagingSenderId: "123456789", appId: "1:123:web:abc" }; const app = initializeApp(firebaseConfig). Then get service instances: import { getFirestore } from "firebase/firestore"; const db = getFirestore(app). Important: (1) The config object is safe to include in client code — Firebase API keys are identifiers, not secrets. Access control is enforced via Security Rules; (2) Call initializeApp() only once (typically in a dedicated firebase.js module); (3) For the Emulator Suite, connect to local emulators: connectFirestoreEmulator(db, "localhost", 8080) for local development.
Practical knowledge for developers with hands-on experience.
01
How do you implement real-time listeners in Firestore?
Real-time listeners use onSnapshot() to receive data and live updates: (1) Document listener: const unsub = onSnapshot(doc(db, "chats", chatId), (snap) => { setMessages(snap.data()) }); (2) Collection listener: const unsub = onSnapshot(query(collection(db, "messages"), orderBy("timestamp"), limit(50)), (snap) => { snap.docChanges().forEach(change => { if (change.type === "added") addMessage(change.doc.data()); if (change.type === "modified") updateMessage(change.doc.id, change.doc.data()); if (change.type === "removed") removeMessage(change.doc.id); }); }); (3) Error handling: pass a second callback: onSnapshot(ref, onNext, onError); (4) Unsubscribe: the function returned by onSnapshot() unsubscribes when called. Always call it when the component unmounts (React: useEffect(() => { return unsub }, [])); (5) Metadata changes: onSnapshot(ref, { includeMetadataChanges: true }, handler) fires on local pending writes too. Listeners are charged as reads on the initial fetch and each change event.
02
How does Firestore querying work?
Firestore queries use a query() function with constraint operators: (1) Filter: where("status", "==", "active"), where("price", "<", 100), where("tags", "array-contains", "sale"), where("status", "in", ["active", "pending"]), where("tags", "array-contains-any", ["sale", "clearance"]), where("category", "not-in", ["deleted"]); (2) Order: orderBy("price", "asc") — must include any filtered field in the first orderBy if using range filter; (3) Limit: limit(10), limitToLast(10); (4) Pagination: startAfter(lastDoc), startAt(value), endBefore(value). Full example: const q = query(collection(db, "products"), where("category", "==", "shoes"), where("price", "<", 100), orderBy("price"), limit(20)); const snaps = await getDocs(q). Compound queries require composite indexes — Firestore shows the index creation link in the console error when an index is missing.
03
What are Firestore composite indexes?
Composite indexes in Firestore are database indexes spanning multiple fields, required for queries that filter or order by more than one field. Firestore automatically creates single-field indexes for each field in every document. For compound queries — like where("category", "==", "shoes").orderBy("price") — Firestore needs a composite index on [category ASC, price ASC]. Without it, the query fails with an error containing a link to create the index. Index management: (1) Automatic — Firebase Console error link auto-populates the index creation form; (2) Manual — define in firestore.indexes.json and deploy with firebase deploy --only firestore:indexes; (3) Exemptions — disable single-field indexes for fields that don't need them (large array fields are expensive to index). Index limitations: maximum 200 composite indexes per database. Each index is billed as a write operation when documents are created/updated. Index propagation can take several minutes for large collections.
04
What are Firestore transactions?
Firestore transactions are atomic operations that read one or more documents, then update them based on the read data — ensuring consistency even with concurrent access. All reads happen before any writes, and the transaction retries automatically if a read document changes before the transaction completes. Example: await runTransaction(db, async (transaction) => { const docRef = doc(db, "accounts", "alice"); const snap = await transaction.get(docRef); if (!snap.exists()) throw new Error("Account not found"); const currentBalance = snap.data().balance; if (currentBalance < 100) throw new Error("Insufficient funds"); transaction.update(docRef, { balance: currentBalance - 100 }); transaction.update(doc(db, "accounts", "bob"), { balance: increment(100) }); }). Transactions: (1) Can read and write across multiple documents; (2) Are limited to 500 document reads/writes; (3) Timeout after 60 seconds; (4) Are retried up to 5 times on contention. Use transactions when reads determine writes. For pure writes without conditional logic, use batch writes instead.
05
What are Firestore batch writes?
Firestore batch writes commit multiple write operations as a single atomic operation — all succeed or all fail. Unlike transactions, batches don't read data — they only write. Supported operations: set, update, delete. Example: const batch = writeBatch(db); batch.set(doc(db, "cities", "NYC"), { name: "New York", state: "NY" }); batch.update(doc(db, "cities", "LA"), { population: increment(1000) }); batch.delete(doc(db, "cities", "OldCity")); await batch.commit(). Batch limits: maximum 500 operations per batch (each set/update/delete counts as one). Benefits over individual writes: (1) Atomicity — all changes apply together or none; (2) Performance — one network round trip instead of N; (3) Consistency — no partial state visible to other readers during batch commit. For deleting large collections, combine pagination with batch deletes: query 500 docs, batch delete, repeat. Batches don't retry on failure and don't read documents (unlike transactions).
06
How does Firebase Authentication work with custom tokens?
Custom tokens allow integrating Firebase Authentication with external authentication systems (LDAP, legacy auth, custom SSO). Flow: (1) User authenticates with your existing auth system (server-side); (2) Your server mints a Firebase custom token using the Firebase Admin SDK: const token = await admin.auth().createCustomToken(userId, { role: "admin", department: "engineering" }); (3) Return token to client; (4) Client signs into Firebase: await signInWithCustomToken(auth, token). The custom token is a short-lived JWT (valid for 1 hour). Once signed in, Firebase issues a standard Firebase ID token that the client can use to authenticate to Firestore and other Firebase services. Custom claims ({ role: "admin" }) are embedded in the token and accessible in Firestore rules: request.auth.token.role == "admin". This pattern bridges existing identity systems with Firebase without requiring users to create new accounts.
07
How do you implement role-based access control with Firestore security rules?
Role-based access control (RBAC) in Firestore uses custom claims and security rules: (1) Set custom claims on the server via Admin SDK: await admin.auth().setCustomUserClaims(uid, { role: "admin" }); (2) Access in rules: function isAdmin() { return request.auth.token.role == "admin"; } match /products/{productId} { allow read: if true; allow write: if isAdmin(); }; (3) User-owned resources: allow write: if request.auth.uid == resource.data.ownerId; (4) Role stored in Firestore: look up user role from Firestore within rules: function getUserRole() { return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role; } allow write: if getUserRole() == "editor". Note: get() in rules costs one read per evaluation; avoid in high-traffic paths. Custom claims are more performant as they're embedded in the auth token. Custom claims are limited to 1000 bytes per user.
08
How does Firebase Cloud Functions work and how do you trigger them?
Firebase Cloud Functions run Node.js code in a managed serverless environment. Functions are deployed with firebase deploy --only functions. Trigger types and examples: (1) HTTPS: exports.createUser = functions.https.onRequest((req, res) => { res.json({ userId: req.body.email }) }); (2) Callable (preferred for client invocation): exports.calculateTotal = functions.https.onCall((data, context) => { if (!context.auth) throw new functions.https.HttpsError("unauthenticated", "Must be logged in"); return { total: data.price * 1.1 }; }). Client calls: const fn = httpsCallable(functions, "calculateTotal"); const result = await fn({ price: 100 }); (3) Firestore trigger: exports.onUserCreate = functions.firestore.document("users/{userId}").onCreate((snap, context) => { const user = snap.data(); return sendWelcomeEmail(user.email) }); (4) Auth trigger: exports.onUserDeleted = functions.auth.user().onDelete(user => deleteUserData(user.uid)); (5) Scheduled: exports.dailyCleanup = functions.pubsub.schedule("every 24 hours").onRun(context => cleanupOldData()).
09
How does Firestore handle offline support?
Firestore has built-in offline persistence that allows apps to continue working without network connectivity. How it works: (1) Local cache — Firestore caches all queried data locally (IndexedDB on web, SQLite on mobile); (2) Offline reads — reads serve data from the local cache when offline, with no code changes needed; (3) Offline writes — writes go to the local cache with a pending status and sync to the server when reconnected; (4) Listen recovery — when reconnected, Firestore automatically syncs pending writes and fetches any changes that occurred while offline. Enabling offline persistence on web (disabled by default): enableIndexedDbPersistence(db) or enableMultiTabIndexedDbPersistence(db) for multi-tab support. On mobile (iOS/Android), it's enabled by default. The DocumentSnapshot.metadata.fromCache property indicates if data came from cache. DocumentSnapshot.metadata.hasPendingWrites indicates if local writes haven't synced yet. Design consideration: offline-capable apps must handle eventual consistency — display pending states in the UI.
10
What is the difference between `set()`, `add()`, and `update()` in Firestore?
These three methods write data but with different behaviors: (1) setDoc(ref, data) — creates OR completely replaces a document at the specified path. If the doc exists, all existing fields are overwritten. If it doesn't exist, it's created. setDoc(doc(db, "users", "alice"), { name: "Alice" }) — you specify the document ID. setDoc(ref, data, { merge: true }) merges instead of overwrites; (2) addDoc(collection, data) — creates a new document with an auto-generated unique ID. Used when you don't care about the document ID. Returns a DocumentReference with the new ID: const ref = await addDoc(collection(db, "posts"), { title: "Hello" }); (3) updateDoc(ref, data) — updates only the specified fields of an existing document. Fails if the document doesn't exist. Does not affect unspecified fields. Summary: setDoc for known IDs (upsert); addDoc for auto-IDs; updateDoc for partial updates on existing docs.
11
How does Firestore pricing work?
Firestore pricing (as of 2024): (1) Document reads — $0.06 per 100,000 reads. Each getDoc() and each document in a query result counts as one read. Real-time listeners charge one read on initial load plus one read per change notification per listening client; (2) Document writes — $0.18 per 100,000 writes (set, add, update, delete each count as one); (3) Document deletes — $0.02 per 100,000 deletes; (4) Stored data — $0.108 per GB/month; (5) Network — free within Google Cloud; egress to internet varies by region. Free tier (Spark plan) includes 50,000 reads, 20,000 writes, 20,000 deletes/day, 1GB storage, 10GB/month network egress. Cost optimization strategies: minimize real-time listeners (use one-time fetches when real-time isn't needed), paginate large queries to avoid fetching unused documents, cache data client-side, batch writes (doesn't reduce write count but reduces network requests), use aggregation queries (COUNT, SUM, AVG — charged as 1 read regardless of matching documents).
12
How do you paginate Firestore queries?
Firestore pagination uses query cursors to split data into pages. Cursor-based pagination (preferred over offset-based): (1) Initial page: const q = query(collection(db, "posts"), orderBy("createdAt", "desc"), limit(10)); const snap = await getDocs(q); const lastDoc = snap.docs[snap.docs.length - 1]; (2) Next page: const nextQ = query(collection(db, "posts"), orderBy("createdAt", "desc"), startAfter(lastDoc), limit(10)); (3) Previous page: store the first document of the current page and use endBefore(firstDoc) with limitToLast(10). For infinite scroll: append data from each page to the list as the user scrolls. For numbered pages: Firestore doesn't support offset pagination natively (offset(n) requires reading and discarding n documents — expensive). The recommended approach is always cursor-based. Store page cursors (document snapshots or document field values) for "jump to page" scenarios if needed. startAt(value) and endAt(value) use field values instead of document snapshots for more control.
13
How do you implement full-text search with Firestore?
Firestore does not support native full-text search — its querying is limited to exact matches, range queries, and array operations. Solutions: (1) Algolia — most popular choice. Sync Firestore data to Algolia via Cloud Functions on write triggers. Algolia provides typo-tolerant, faceted full-text search with client-side SDKs; (2) Typesense — open-source Algolia alternative; self-hosted or cloud; (3) Elasticsearch/OpenSearch — most powerful but most complex; stream Firestore data via Cloud Functions to an Elasticsearch cluster; (4) Firebase Extensions — the Search with Algolia and Search with Typesense extensions automate Firestore-to-search-provider sync without custom Cloud Functions; (5) Client-side prefix matching — for simple prefix search (not full-text), use: query(collection(db, "users"), orderBy("name"), startAt(searchTerm), endAt(searchTerm + "")). The character is the highest Unicode character, making the range match all strings starting with searchTerm; (6) Vector search — Firestore now supports vector embeddings for semantic/AI-powered search.
14
What is Firebase App Check?
Firebase App Check protects your Firebase backend resources (Firestore, Cloud Functions, Realtime Database, Storage) from abuse by ensuring requests come from your legitimate app — not bots, scripts, or unauthorized clients. How it works: (1) Attestation providers — App Check integrates with platform-specific attestation: App Attest (iOS 14+), Play Integrity (Android), and reCAPTCHA Enterprise (web); (2) Token issuance — the attestation provider verifies the app is legitimate and issues a short-lived App Check token; (3) Token enforcement — Firebase services validate the App Check token on every request and reject requests without valid tokens. Enforcement modes: monitor (log but allow) and enforce (block unverified requests). Benefits: prevents API scraping, credential stuffing, and unauthorized Firestore reads that inflate your billing. App Check complements Security Rules — Rules control who can access what; App Check verifies the request comes from a genuine app instance.
15
How do you use Firestore with React?
The recommended approach for Firestore in React uses the reactfire library or custom hooks. Custom hook pattern: function useDocument(path) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const unsub = onSnapshot(doc(db, ...path.split("/")), snap => { setData(snap.data()); setLoading(false); }); return unsub; }, [path]); return { data, loading }; }. Usage: const { data: user, loading } = useDocument("users/alice"). With reactfire library: const userRef = doc(getFirestore(), "users", "alice"); const { status, data } = useFirestoreDocData(userRef). With SWR or React Query: wrap Firestore fetches in query functions for caching, revalidation, and loading states. Key patterns: (1) Always unsubscribe real-time listeners in useEffect cleanup; (2) Avoid excessive listeners — one listener per required data source; (3) Memoize references — doc(db, ...) creates new objects on each render; memoize with useMemo to prevent infinite re-renders; (4) Use the Firebase Emulator for local development.
16
What is FieldValue in Firestore?
FieldValue (in SDK v9: individual functions) provides special sentinel values for atomic field operations that the server executes: (1) serverTimestamp() — sets the field to the server's current timestamp. Use this instead of new Date() to avoid clock skew across devices; (2) increment(n) — atomically increments (or decrements with negative n) a numeric field. Safe for concurrent updates — use for view counts, like counts, inventory: updateDoc(ref, { viewCount: increment(1) }); (3) arrayUnion(value) — adds elements to an array only if not already present. Safe for concurrent updates — use for tags, category lists; (4) arrayRemove(value) — removes all occurrences of the value from an array; (5) deleteField() — removes a field from the document entirely. These operations are atomic — they don't require a transaction, even under concurrent access, because the server resolves them. Without increment(), counting requires a transaction (read-then-write), which is slower and more prone to contention.
17
What is Firebase Emulator Suite?
The Firebase Emulator Suite is a set of local emulators for Firebase services that allow development and testing without touching production data or incurring production costs. Available emulators: Firestore, Authentication, Realtime Database, Cloud Storage, Cloud Functions, Hosting, Pub/Sub, Extensions. Setup: install the Firebase CLI, run firebase emulators:start, connect your app: connectFirestoreEmulator(db, "localhost", 8080); connectAuthEmulator(auth, "http://localhost:9099"). Features: (1) Emulator UI — web UI at localhost:4000 to view and edit data, trigger functions, manage users; (2) Import/export — --import=./seed-data pre-populates emulator with seed data; (3) Test isolation — each test can clear emulator data; (4) Rules testing — test security rules locally with the Rules Simulator and @firebase/rules-unit-testing library. The Emulator Suite is essential for teams who want fast iteration, complete test coverage of security rules, and zero risk of affecting production data during development.
Deep expertise questions for senior and lead roles.
01
How do you design a scalable data model in Firestore?
Firestore data modeling differs fundamentally from SQL: you optimize for read performance over normalization. Principles: (1) Design for queries first — start with the queries your app needs, then design the data structure to support them. Firestore can't JOIN documents; (2) Denormalization is expected — duplicate data to avoid fetching multiple documents. Store the author's name in each post document, not just the author's ID; (3) Choose between top-level collections vs. subcollections — subcollections for data that's only queried in the context of its parent; top-level collections when cross-collection queries are needed; (4) Fan-out writes — for social feeds, when a user posts, write to each follower's feed collection (write amplification, but enables O(1) reads per user); (5) Avoid large arrays — Firestore loads the entire document including arrays; large arrays slow reads and hit the 1MB limit; use subcollections instead; (6) Use aggregation documents — maintain counter/aggregate documents updated via Cloud Functions on writes; (7) Map fields vs. subcollections — maps work for bounded, small datasets; subcollections for potentially large, growing lists; (8) 1:N relationships — store the "many" side's parent ID as a field and query by it.
02
How do you handle Firestore rate limits and quota exhaustion?
Firestore has documented limits that applications must respect: (1) Write rate per document — maximum 1 write/second per document. For high-frequency counters (views, likes), this is a critical constraint; (2) Sustained write rate — new collections and indexes have warming periods; very high initial write rates may hit "resource exhausted" errors; (3) Index write overhead — each indexed field generates additional writes; too many indexes slow writes. Solutions for rate limits: (1) Distributed counters — split a single counter into N shards (e.g., 10 documents), each supporting 1 write/second; total capacity: 10 writes/second; reads sum all shards; (2) Write batching — batch writes with writeBatch() for better throughput; (3) Queue-based writes — buffer writes through Pub/Sub or Cloud Tasks, then write at a controlled rate; (4) Exponential backoff — on "resource exhausted" (429) errors, retry with exponential backoff and jitter; (5) Increase quota — contact Google Cloud support to raise limits for production workloads. Monitor Firestore quotas in the Firebase console under Usage.
03
How do you implement distributed counters in Firestore?
Firestore's 1 write/second per document limit makes naive counters (increment a single field) insufficient for high-traffic scenarios. The distributed counter pattern solves this by spreading writes across multiple documents: (1) Initialize shards: for (let i = 0; i < NUM_SHARDS; i++) { setDoc(doc(db, "counters", `likes_${i}`), { count: 0 }) }; (2) Increment: pick a random shard and increment: const shardId = Math.floor(Math.random() * NUM_SHARDS); await updateDoc(doc(db, "counters", `likes_${shardId}`), { count: increment(1) }); (3) Read total: sum all shards: const snaps = await getDocs(collection(db, "counters")); const total = snaps.docs.reduce((sum, d) => sum + d.data().count, 0). With 10 shards: 10 writes/second capacity. With 100 shards: 100 writes/second. Trade-off: reads become more expensive (N document reads instead of 1). For read-heavy counters, cache the aggregated total in a separate document updated periodically by Cloud Functions. The newer Firestore aggregation queries (getCountFromServer(), getAggregateFromServer()) provide server-side counting without reading all documents.
04
How do you migrate from Firebase Realtime Database to Firestore?
Migration strategy from Realtime Database (RTDB) to Firestore: (1) Data export — export RTDB data as JSON from the Firebase console; (2) Data model redesign — RTDB uses a flat JSON tree; Firestore uses collections/documents. Don't just convert 1:1 — redesign for Firestore's query model. RTDB arrays become subcollections or map fields; deeply nested JSON becomes separate collections; (3) Import script — write a Node.js script using Admin SDK to read exported JSON and write to Firestore in batches (500 docs per batch): const batch = admin.firestore().batch(); users.forEach(user => { batch.set(db.collection("users").doc(user.id), transform(user)) }); await batch.commit(); (4) Dual-write period — write to both RTDB and Firestore simultaneously during migration; reads come from Firestore; validate consistency; (5) Security rules migration — RTDB rules have different syntax than Firestore rules; rewrite from scratch following Firestore patterns; (6) SDK changes — update all client code to use Firestore SDK (different API surface); (7) Cutover — switch reads to Firestore-only after validation; disable RTDB writes; (8) Cost modeling — Firestore pricing is per-operation, not bandwidth; model the cost impact before migrating.
05
What are the performance optimization techniques for Firestore queries?
Firestore query performance optimization: (1) Index optimization — ensure composite indexes exist for all multi-field queries. Missing indexes cause queries to fail; extra indexes slow writes and increase storage costs. Audit indexes regularly; (2) Limit data fetched — use limit() to fetch only needed documents; use select() (field masks) to fetch only needed fields: query(collection(db, "users"), select("name", "email"), limit(20)); (3) Avoid large document reads — don't store large binary data or huge arrays in documents; use Cloud Storage for files; (4) Aggregate queries — use getCountFromServer() and getAggregateFromServer() instead of fetching all documents to count: cheaper and faster; (5) Client-side caching — cache frequently accessed, rarely changing data (user profiles, settings) in memory or localStorage; (6) Reduce listener count — each active listener consumes resources; merge multiple document listeners into one collection query where possible; (7) Pagination — never fetch unbounded collections; always paginate with limit(); (8) Composite index order — equality fields first, then range/order fields in composite indexes; (9) Colocation — use the nearest Firestore region to reduce latency.
06
How do you implement multi-tenant architecture with Firebase?
Multi-tenancy with Firebase can be implemented at different isolation levels: (1) Data isolation with security rules — store a tenantId field in every document; rules enforce tenant boundaries: allow read: if request.auth.token.tenantId == resource.data.tenantId. Simplest approach, lowest cost, but no complete tenant isolation; (2) Collection-per-tenant — prefix all collections with tenant ID: /tenants/{tenantId}/users/{userId}. Enables per-tenant queries easily; rules protect cross-tenant access; (3) Firebase project-per-tenant — each enterprise customer gets their own Firebase project. Complete data isolation, separate billing, separate security rules. Most secure but complex to manage (Admin SDK multi-project initialization, separate Firebase console access); (4) Firebase Auth tenants — Firebase Identity Platform (paid) supports multi-tenancy in Firebase Auth natively with tenant-specific sign-in providers, users, and settings. Custom tokens include a tenant_id; Firestore rules can check request.auth.firebase.tenant; (5) Hybrid — Firebase Auth tenants for identity + collection-per-tenant for data. This is the recommended enterprise approach.
07
How do you backup and restore Firestore data?
Firestore backup and restore options: (1) Managed Backups (generally available since 2024) — Firestore supports automated daily backups retained for 7 days in the same region. Configure via Firebase console or gcloud: gcloud firestore backups schedules create --database="(default)" --recurrence=daily --retention=1w. Restore: gcloud firestore databases restore --source-backup=backup-name --destination-database=restored-db; (2) Point-in-time recovery (PITR) — read data as it was up to 7 days in the past using the readTime parameter. Useful for recovering from accidental deletes: await getDocs(query(collection(db, "users")), { readTime: Timestamp.fromDate(oneDayAgo) }); (3) Export to Cloud Storage — gcloud firestore export gs://my-bucket/backups/$(date +%Y%m%d) exports all data to Cloud Storage as Avro files. Automatable with Cloud Scheduler + Cloud Functions; (4) BigQuery export — stream Firestore data to BigQuery for analytical backups via the Firestore → BigQuery extension; (5) Custom backup scripts — read all documents via Admin SDK and serialize to JSON/CSV; suitable for small databases. Test restore procedures regularly — backup without tested restore is not a backup.
08
What is Firebase Extensions and how do you use them?
Firebase Extensions are pre-packaged, open-source solutions that add functionality to your Firebase app with minimal code. They are managed, auto-updating Cloud Functions that respond to Firebase events. Popular extensions: (1) Trigger Email — monitors a Firestore collection for email documents and sends them via SendGrid/Mailchimp/SMTP; (2) Resize Images — automatically creates multiple resized versions of uploaded images to Firebase Storage; (3) Search with Algolia — syncs Firestore data to Algolia for full-text search automatically; (4) Delete User Data — deletes all Firestore, RTDB, and Storage data for a user when their account is deleted (GDPR compliance); (5) Stripe Payments — manages customer subscriptions and payments; (6) Translate Text — translates text in Firestore documents using Cloud Translation API. Install via CLI: firebase ext:install firebase/firestore-send-email. Extensions are configured with environment variables during installation and deployed as Cloud Functions in your project. They are open-source (GitHub: firebase/extensions) — you can inspect, fork, and self-host them.
09
How do you implement server-side rendering with Firebase?
Server-Side Rendering (SSR) with Firebase can be implemented through several approaches: (1) Firebase Hosting + Cloud Functions — use Cloud Functions as the SSR server. Express.js function renders the React/Vue app server-side: the function fetches Firestore data using the Admin SDK (no auth required for server), renders HTML, returns it. Firebase Hosting rewrites route traffic to the function. This is Firebase's native SSR approach; (2) Firebase Hosting + Cloud Run — deploy a Docker container (Next.js, Nuxt.js SSR server) to Cloud Run; Firebase Hosting rewrites to the Cloud Run URL. Preferred for complex SSR apps with long cold starts that benefit from container warming; (3) Next.js + Firebase Framework Hosting — firebase experiments:enable webframeworks enables automatic Next.js deployment to Firebase with SSR detected automatically; API routes → Cloud Functions; SSR pages → dynamic rendering; static pages → CDN. (4) Admin SDK for server-side Firestore — SSR servers must use the Admin SDK (not the client SDK) to bypass Security Rules: const admin = require("firebase-admin"); admin.initializeApp(); const db = admin.firestore(). Use service account credentials for the Admin SDK in Cloud Functions (auto-configured) or Cloud Run (manual service account setup).
10
What are the security best practices for Firebase applications?
Comprehensive Firebase security best practices: (1) Never use permissive rules in production — rules like allow read, write: if true expose all data. Always require authentication minimum; (2) Validate data in security rules — check data types, required fields, and value ranges: allow create: if request.resource.data.age is int && request.resource.data.age > 0 && request.resource.data.age < 150; (3) Test security rules — use the Firebase Rules Simulator and @firebase/rules-unit-testing. Deploy rules changes to staging first; (4) Enable App Check — prevent unauthorized API access from scripts and bots; (5) Use Firebase Auth for all user actions — never allow anonymous writes to sensitive collections; (6) Server-side validation in Cloud Functions — don't trust client data; validate in Cloud Functions even if rules allow the write; (7) Audit Admin SDK usage — Admin SDK bypasses security rules; restrict who deploys Cloud Functions; use service accounts with minimum required permissions; (8) Monitor for anomalies — set up budget alerts; monitor read/write rates; high unexpected traffic may indicate a misconfigured rule or a scraping attack; (9) Rotate API keys periodically — Firebase API keys are publicly visible in client code but restrict them in Google Cloud Console by HTTP referer (web) or package name (mobile); (10) HTTPS only — Firebase Hosting enforces HTTPS automatically; use wss:// for Realtime Database.