docs/articles/firestore-alternative.html
On this page
If you're seeking a Firestore alternative , you're likely looking for a way to:
Enter RxDB (Reactive Database) - a local-first, NoSQL database for JavaScript applications that can sync in real time with any backend of your choice. Whether you're tired of the limitations and fees associated with Firebase Cloud Firestore or simply need more flexibility, RxDB might be the Firestore alternative you've been searching for.
Firestore is convenient for many projects, but it does lock you into Google's ecosystem. Below are some of the key advantages you gain by choosing RxDB:
RxDB runs directly in your client application (browser, Node.js, Electron, React Native, etc.). Data is stored locally, so your application remains fully functional even when offline. When the device returns online, RxDB's flexible replication protocol synchronizes your local changes with any remote endpoint.
Unlike Firestore, RxDB doesn't require a proprietary hosting service. You can:
This backend-agnostic approach protects you from vendor lock-in. Your application's client-side data storage remains consistent; only your replication logic (or plugin) changes if you switch servers.
Firestore enforces a last-write-wins conflict resolution strategy. This might cause issues if multiple users or devices update the same data in complex ways.
RxDB lets you:
Firestore queries often count as billable reads. With RxDB, queries run locally against your local state - no repeated network calls or extra charges. You pay only for the data actually synced, not every read. For read-heavy apps, using RxDB as a Firestore alternative can significantly reduce costs.
Firestore's query engine is limited by certain constraints (e.g., no advanced joins, limited indexing). With RxDB:
While Firestore does have offline caching, it often requires an online check at app initialization for authentication. RxDB is truly offline-first; you can launch the app and write data even if the device never goes online initially. It's ready whenever the user is.
RxDB is designed to run in any environment that can execute JavaScript. Whether you’re building a web app in the browser, an Electron desktop application, a React Native mobile app, or a command-line tool with Node.js, RxDB’s storage layer is swappable to fit your runtime’s capabilities.
#Does Firebase Firestore qualify as a robust offline sync engine?
While Firestore provides basic offline caching, it is fundamentally a cloud-first database. True Offline-First architectures demand that the local database acts as the single source of truth, capable of advanced local querying, custom indexing, and deterministic conflict resolution without ever contacting a server. Firestore's heavy reliance on Google Cloud connections makes it unsuitable for applications that must operate reliably in zero-connectivity environments for extended periods.
RxDB replication is powered by its own Sync Engine. This simple yet robust protocol enables:
Code Example: Sync RxDB with a Custom Backend
import { createRxDatabase } from 'rxdb/plugins/core';
import { getRxStorageLocalstorage } from 'rxdb/plugins/storage-localstorage';
import { replicateRxCollection } from 'rxdb/plugins/replication';
async function initDB() {
const db = await createRxDatabase({
name: 'mydb',
storage: getRxStorageLocalstorage(),
multiInstance: true,
eventReduce: true
});
await db.addCollections({
tasks: {
schema: {
title: 'task schema',
version: 0,
type: 'object',
primaryKey: 'id',
properties: {
id: { type: 'string', maxLength: 100 },
title: { type: 'string' },
done: { type: 'boolean' }
}
}
}
});
// Start a custom REST-based replication
replicateRxCollection({
collection: db.tasks,
replicationIdentifier: 'my-tasks-rest-api',
push: {
handler: async (documents) => {
// Send docs to your REST endpoint
const res = await fetch('https://myapi.com/push', {
method: 'POST',
body: JSON.stringify({ docs: documents })
});
// Return conflicts if any
return await res.json();
}
},
pull: {
handler: async (lastCheckpoint, batchSize) => {
// Fetch from your REST endpoint
const url = 'https://myapi.com/pull' +
`?checkpoint=${JSON.stringify(lastCheckpoint)}` +
`&limit=${batchSize}`;
const res = await fetch(url);
return await res.json();
}
},
live: true // keep watching for changes
});
return db;
}
By swapping out the handler implementations or using an official plugin (e.g., GraphQL, CouchDB, Firestore replication, etc.), you can adapt to any backend or data source. RxDB thus becomes a flexible alternative to Firestore while maintaining real-time capabilities.
npm install rxdb rxjs
import { createRxDatabase } from 'rxdb/plugins/core';
import { getRxStorageLocalstorage } from 'rxdb/plugins/storage-localstorage';
const db = await createRxDatabase({
name: 'mydb',
storage: getRxStorageLocalstorage()
});
await db.addCollections({
items: {
schema: {
title: 'items schema',
version: 0,
primaryKey: 'id',
type: 'object',
properties: {
id: { type: 'string', maxLength: 100 },
text: { type: 'string' }
}
}
}
});
Use a Replication Plugin to connect with a custom backend or existing database.
For a Firestore-specific approach, RxDB Firestore Replication also exists if you want to combine local indexing and advanced queries with a Cloud Firestore backend. But if you really want to replace Firestore entirely - just point RxDB to your new backend.
In addition to syncing with a central server, RxDB also supports pure peer-to-peer replication using WebRTC. This can be invaluable for scenarios where clients need to sync data directly without a master server.
import {
replicateWebRTC,
getConnectionHandlerSimplePeer
} from 'rxdb/plugins/replication-webrtc';
const replicationPool = await replicateWebRTC({
collection: db.tasks,
topic: 'my-p2p-room', // Clients with the same topic will sync with each other.
connectionHandlerCreator: getConnectionHandlerSimplePeer({
// Use your own or the official RxDB signaling server
signalingServerUrl: 'wss://signaling.rxdb.info/',
// Node.js requires a polyfill for WebRTC & WebSocket
wrtc: require('node-datachannel/polyfill'),
webSocketConstructor: require('ws').WebSocket
}),
pull: {}, // optional pull config
push: {} // optional push config
});
// The replicationPool manages all connected peers
replicationPool.error$.subscribe(err => {
console.error('P2P Sync Error:', err);
});
This example sets up a live P2P replication where any new peers joining the same topic automatically sync local data with each other, eliminating the need for a dedicated central server for the actual data exchange.
If you've been searching for a Firestore alternative that gives you the freedom to sync your data with any backend, offers robust offline-first capabilities, and supports truly customizable conflict resolution and queries, RxDB is worth exploring. You can adopt it seamlessly, ensure local reads, reduce costs, and stay in complete control of your data layer.
Ready to dive in? Check out the RxDB Quickstart Guide, join our Discord community, and experience how RxDB can be the perfect local-first, real-time database solution for your next project.
More resources: