Choosing Between Cloud Firestore and Realtime Database for Mobile Sync
A concise guide to decide between Cloud Firestore and Realtime Database for mobile sync, with a feature table, trade‑off analysis, and validation steps.
06 Jun 2026, 15:28 UTC

Decision and Constraints
When building a mobile app that needs real‑time data synchronization, you must decide whether to use Cloud Firestore or the original Realtime Database. The decision hinges on data model complexity, query needs, expected scale, and cost profile. Constraints often include:
- Need for hierarchical data or sub‑collections.
- Requirement for compound queries or array‑contains filters.
- Expected concurrent client count and write throughput.
- Budget sensitivity to frequent tiny updates vs. larger payloads.
- Desired granularity of security rules.
Option Comparison
| Feature | Cloud Firestore | Realtime Database |
|---|---|---|
| Data model | Document‑oriented with sub‑collections | Single large JSON tree |
| Queries | Compound filters, array‑contains, IN, collection‑group | Shallow queries, limited to one filter or order‑by per property |
| Offline persistence | Configurable per platform, uses IndexedDB (web) or SQLite (native) | Automatic caching of subscribed subtree |
| Scaling | Automatic sharding, optional multi‑region | Limited by concurrent connections per instance; may need multiple DBs |
| Pricing | Per document read/write/delete + storage + bandwidth | Storage + data downloaded (no per‑operation charge) |
| Security rules | Field‑level conditions, resource metadata | Path‑based cascading rules with variable capture |
| Transactions | Multi‑document transactions, batched writes | Atomic update at a single JSON path only |
Trade‑offs
Firestore excels when your app needs rich queries, hierarchical data, or fine‑grained security. Its automatic scaling removes the need to shard manually, but you must manage composite indexes and monitor per‑operation costs. Realtime Database is simpler for apps that primarily sync small, frequent updates (e.g., presence indicators) and where a flat JSON tree suffices. However, its query capabilities are limited, and scaling beyond a few thousand concurrent connections often requires provisioning additional database instances.
Concrete Implementation: Enabling Firestore Persistence
Below is a minimal snippet showing how to turn on persistence for each platform. Place the code in your app’s initialization routine (e.g., Application.onCreate on Android, application(_:didFinishLaunchingWithOptions:) on iOS, or the main script for a web app).
// Android (Java)
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(true)
.build();
FirebaseFirestore.getInstance().setFirestoreSettings(settings);
// iOS (Swift)
let settings = FirestoreSettings()
settings.isPersistenceEnabled = true
let db = Firestore.firestore()
db.settings = settings
// Web (JavaScript)
import { initializeApp } from 'firebase/app';
import { getFirestore, enableIndexedDbPersistence } from 'firebase/firestore';
const firebaseApp = initializeApp(firebaseConfig);
const db = getFirestore(firebaseApp);
enableIndexedDbPersistence(db).catch((err) => {
if (err.code === 'failed-precondition') {
// Multiple tabs open, persistence can only be enabled in one tab
} else if (err.code === 'unimplemented') {
// Browser does not support required features
}
});
After deploying, you can verify that persistence is active by disconnecting the network, performing a write, reconnecting, and confirming that the write is applied locally and then sent to the server.
Validation Steps
- Create a test Firebase project and enable both Firestore and Realtime Database.
- Instrument the app to perform a fixed workload: 100 writes of 1 KB each and 100 reads of varying sizes over a 30‑second window.
- Run the workload twice—once against Firestore, once against Realtime Database—while monitoring the Usage tab in the Firebase console for each service.
- Record latency (average round‑trip time) and quota consumption (reads/writes for Firestore, concurrent connections and data downloaded for Realtime Database).
- For Firestore, issue a query that requires a composite index (e.g.,
where('age', '>', 18).where('city', '==', 'San Francisco')). Confirm the SDK returns an index‑creation prompt, create the index via the console, and re‑run the query to verify success. - For Realtime Database, open the Usage panel while simulating 2 000 concurrent clients (using a load‑testing tool) and observe whether the concurrent‑connection count approaches the plan limit.
These steps give you empirical data to compare the two services under your specific workload.
Limitations and Practical Checks
- Firestore web persistence relies on IndexedDB, which may be cleared by browser storage pressure or incognito mode, leading to unexpected cache misses. Check persistence by inspecting
navigator.storage.persist()or by observing whether local writes survive a page reload. - Realtime Database’s concurrent‑connection limit can drop clients in chat or IoT scenarios. Verify by watching the Usage → Realtime Database → Connections graph while gradually increasing client count.
- Migrating data from Realtime Database to Firestore is manual; there is no automated schema conversion. Plan a migration script if you anticipate switching later.
By following the comparison table, reviewing the trade‑offs, and executing the validation steps, you can make an evidence‑based choice that matches your app’s synchronization requirements.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.