How to Use RxDB: The Beginner's Guide (First Database, First Collection, and the Reactive Payoff)
CodexFuse Team · 2026-11-02T08:33:26.009Z · 15 min read min read
RxDB is a local-first, reactive NoSQL database for JavaScript apps. This beginner guide covers install, storage choice, your first database and collection, reactive queries, and replication.
How to Use RxDB: The Beginner's Guide (First Database, First Collection, and the Reactive Payoff)
Learning how to use RxDB starts with one mental shift: your JavaScript app does not need a server to have a database. RxDB puts a real, reactive, offline-first database directly inside your app — in the browser, in a Node.js process, or on a phone — and only talks to a backend when you explicitly ask it to sync. This RxDB tutorial is written as an RxDB for beginners guide: the full arc from install to your first reactive query, verified against the official docs and GitHub README on November 2, 2026. If you searched "how to use rxdb" or "rxdb tutorial" and found scattered framework walkthroughs, this page is the missing unified beginner guide. One disambiguation up front, because the names rhyme: PowerSync beginner guide covers a different lane — PowerSync is a managed sync engine that mirrors your Postgres into a local SQLite file; RxDB is the reactive NoSQL database your app code runs against, with optional replication plugins you control. Database versus sync service — say the line once, and the rest of this guide makes sense.
What Is RxDB, Exactly?
RxDB (short for Reactive Database) is a local-first, NoSQL database for JavaScript applications. That is the project's own description on its GitHub README (pubkey/rxdb), where it headlines itself as "a fast, local-first, reactive database for JavaScript applications" with the tagline "the local-first database that runs on every JS runtime and replicates with your existing backend — no vendor, no lock-in." Local-first means the data lives where your app runs: reads and writes hit the local store first, at near-zero latency, and the app works fully offline. Reactive means your UI subscribes to query results and updates the moment the underlying data changes — no manual refetch, no refresh button, no polling loop. JavaScript means everywhere: the same database engine runs in browsers, Node.js, Deno, Capacitor/Ionic apps, and React Native. As of this writing (verified November 2, 2026), the project carries about 23,424 GitHub stars — a moving snapshot, not a promise — dates back to a 2016 creation, and ships under the Apache 2.0 license, which matters if you plan to build a commercial product on it. The rest of this guide shows you what to do with it.
What Do You Need Before You Start?
You need a working JavaScript environment and a terminal you are comfortable in. RxDB is an npm package, so Node.js with npm installed is the baseline — the official quickstart assumes you can run npm install and a bundler or module setup. You also need the one mental prerequisite this whole guide is built around: think of RxDB as a client-side database, not a server you deploy. If you have never worked with a reactive stream before, basic RxJS familiarity helps, because RxDB ships its reactivity on RxJS observables (you install rxjs alongside rxdb). Version-control your schema files from day one — our Git beginner guide covers the setup — because schema versions are how RxDB handles data migrations, and you will meet them in the collection section below. The table is your one-minute readiness check.
| Prerequisite | What "ready" looks like | Why it matters for RxDB |
|---|---|---|
| Node.js + npm | npm --version prints a version | RxDB installs from the npm registry |
| A JS project | A folder with a bundler or plain modules | RxDB runs inside your app, not on a server |
| RxJS basics | You know what subscribe means | Reactive queries are RxJS observables |
| Git for your schema files | A repo for the project | Schema versions drive migrations later |
How Do You Install RxDB?
You install RxDB with a single npm command, said once: npm install rxdb rxjs. That is the official quickstart's instruction verbatim (rxdb.info/quickstart.html), and the two packages are a pair — rxdb is the database, rxjs is the reactive engine its queries are built on. As of this writing the npm registry serves RxDB 17.6.0 (verified November 2, 2026 — versions move, so treat the number as a snapshot and check npm for the latest before you pin it). One caution that saves beginners real pain, verified against the live docs today: RxDB's import paths moved to the rxdb/plugins/* layout in version 15 and later, and the current quickstart uses it throughout — createRxDatabase from 'rxdb/plugins/core', plugins from 'rxdb/plugins/
npm install rxdb rxjs
Which RxDB Storage Should You Choose?
Choosing a storage is the single most important decision in RxDB, so make it deliberately and say it once. RxDB separates the database engine from the persistence layer: you pass a storage plugin to createRxDatabase, and the same database code runs on top of any of them. The README's full storage list is LocalStorage, IndexedDB, OPFS, LokiJS, Dexie.js, in-memory, SQLite, WebWorker thread, FoundationDB, and DenoKV — but beginners realistically pick from four. Dexie (IndexedDB) is the default browser pick: fast, persistent, and free. LocalStorage is the simplest for prototypes — zero setup — but slow and size-limited. In-memory is for unit tests and throwaway sessions: everything vanishes when the process exits, and Node.js caps its heap near 4 GB unless you raise it. The free/paid line, said once: the SQLite trial storage (getRxStorageSQLiteTrial from 'rxdb/plugins/storage-sqlite', which ships in RxDB Core on built-in node:sqlite) is capped at 500 documents with no indexes and is prototypes-only; the full SQLite storage, the premium IndexedDB storage, the memory-mapped storage, and the web-crypto encryption plugin are paid Premium plugins. The Ionic team's own published path is the template: prototype on the free LocalStorage storage, then swap in the Premium SQLite storage for production mobile. Node.js developers get one extra rule from the docs: the LocalStorage API does not exist in Node (you get "ReferenceError: localStorage is not defined"), so server-side code starts at Dexie/SQLite/FoundationDB instead.
| Storage | Where it shines | Cost | Beginner note |
|---|---|---|---|
| Dexie (IndexedDB) | Default browser persistence | Free | The default pick for web apps |
| LocalStorage | Prototypes, tiny datasets | Free | Simple but slow; Ionic path starts here |
| In-memory | Unit tests, scratch sessions | Free | Data lost on process exit |
| SQLite trial | Prototyping the SQLite lane | Free, 500-document cap, no indexes | Prototypes only |
| SQLite (full) | Production mobile and desktop | Paid Premium | The Ionic production target |
| FoundationDB | Node.js horizontal scaling | Free | Cluster file config; SQLite is faster per node but vertical-only |
How Do You Create Your First RxDB Database?
You create your first RxDB database with one async call: await createRxDatabase({ name: 'mydatabase', storage }). The name identifies the database on disk (or in the chosen storage), and storage is the plugin instance from the section above — for example getRxStorageDexie() for IndexedDB. Two practices from the official quickstart belong here. First, enable the dev-mode plugin during development — addRxPlugin(RxDBDevModePlugin) from 'rxdb/plugins/dev-mode' — because it adds checks and validations that catch schema mistakes early; but dev-mode is dev-only, never ship it to production, said once. Second, wrap your storage with schema validation (wrappedValidateAjvStorage from 'rxdb/plugins/validate-ajv'): the quickstart treats validation as required in dev-mode and strongly recommended in production, and it is the thing that turns "the schema says so" from a comment into an enforced rule.
import { createRxDatabase, addRxPlugin } from 'rxdb/plugins/core';
import { RxDBDevModePlugin } from 'rxdb/plugins/dev-mode';
import { getRxStorageDexie } from 'rxdb/plugins/storage-dexie';
addRxPlugin(RxDBDevModePlugin); // development only — never ship this
const myDatabase = await createRxDatabase({
name: 'mydatabase',
storage: getRxStorageDexie()
});
How Do You Create Your First Collection?
You create your first collection with addCollections, passing a JSON-Schema document that describes the collection's shape. The quickstart's rules, said once because they bite every beginner: every schema carries a version number (start at 0 — you bump it when the shape changes, and RxDB migrates data between versions), the schema names a primaryKey, and the primary-key field must declare a maxLength (this is the oddest rule and the most common first error). The example below builds a todos collection with a title string, a done boolean, and a dueAt timestamp. If your app queries by a field often — due dates are the classic case — declare it in the schema's indexes array (the Angular article's example indexes 'dueAt'), because indexes are the difference between a fast query and a full scan as the collection grows.
await myDatabase.addCollections({
todos: {
schema: {
version: 0,
primaryKey: 'id',
type: 'object',
properties: {
id: { type: 'string', maxLength: 100 },
title: { type: 'string' },
done: { type: 'boolean' },
dueAt: { type: 'string', format: 'date-time' }
},
required: ['id', 'title', 'done'],
indexes: ['dueAt']
}
}
});
How Do You Insert and Query Documents?
You insert documents with collection.insert and query them with collection.find — and this is the RxDB quickstart lane, the exact "rxdb quickstart" flow from the official docs. Insert is a promise: await myDatabase.todos.insert({ id: 'task-1', title: 'Buy milk', done: false }). Querying uses a selector syntax — await myDatabase.todos.find({ selector: { done: { $eq: false } } }).exec() — where .exec() runs the query once and returns the matching documents. Updates go through the document: firstDocument.patch({ done: true }) changes one field, firstDocument.remove() deletes it. Notice the philosophy: queries describe what you want (a selector), the storage plugin decides how to run it, and the schema validation from the database section already checked every insert against your JSON-Schema before it landed.
const doc = await myDatabase.todos.insert({
id: 'task-1',
title: 'Buy milk',
done: false
});
const openTodos = await myDatabase.todos
.find({ selector: { done: { $eq: false } } })
.exec();
await doc.patch({ done: true });
How Does RxDB Reactivity Actually Work?
RxDB reactivity is the whole payoff of this library: subscribe to a query once, and your UI updates itself every time the data changes. Here is the one "realtime" line, said once: RxDB's realtime is local reactivity plus optional replication — it is not a server pushing events to you. The quickstart's pattern is myDatabase.todos.find({ selector: { done: { $eq: false } } }).$ — the trailing $ turns the query into an observable — followed by .subscribe(todos => render(todos)), and that subscription fires on insert, patch, remove, replication arrivals, and even changes made in another browser tab. You can also observe a single document field: myDocument.done$.subscribe(done => ...) fires only when that one field changes. Framework notes for the two biggest audiences: React developers subscribe inside components the RxJS way (useEffect plus local state — the quickstart's own React-adjacent examples lean on RxJS primitives); Angular developers get a dedicated lane in RxDB's own Angular/IndexedDB article (updated October 19, 2026): observables run outside Angular's zone, so import 'zone.js/plugins/zone-patch-rxjs' for change detection, and use the $ Signal accessor with the RxReactivityFactory plus toSignal to turn a query into an Angular Signal. The cross-tab behavior deserves one more look, because it surprises people: two tabs of the same app share the storage, so subscribing in one tab shows changes written by the other — reactivity as collaboration, with zero backend involved.
How Do You Replicate RxDB to a Backend?
You replicate RxDB to a backend with the replication plugin, and replication is explicitly optional — local-first means the database is complete without it. The quickstart's HTTP pattern is replicateHTTP({ collection, push: { handler }, pull: { handler } }) from 'rxdb/plugins/replication-http': you supply a push handler that sends local changes to your server and a pull handler that fetches remote changes, and RxDB runs the sync loop with conflict handling around them. The README's replication targets show how wide the lane is: GraphQL, CouchDB, Websocket, WebRTC for peer-to-peer, Supabase, Firestore, NATS, and Google Drive — and the underlying sync protocol is just three simple HTTP endpoints, so rolling your own backend is a documented option rather than a hack. If your backend is a server you run yourself, containerizing it is the clean path — our Docker beginner guide walks the setup. This is also where the intro's line earns its keep: replication is a plugin you bolt onto RxDB, the database; if you want the sync layer as a managed service with its own dashboard, that is the PowerSync lane, not this one.
Should You Encrypt or Compress Your RxDB Data?
You encrypt RxDB data at the field level when the stored data is sensitive, and the docs give you both a free lane and a paid lane. RxDB's own Ionic article (updated October 19, 2026) marks fields for AES encryption directly in the schema — encrypted: ['ssn'] — with one hard rule: encrypted fields cannot be queried directly, so never encrypt a field you filter or sort on. The free lane is the crypto-js plugin (wrappedKeyEncryptionCryptoJsStorage from 'rxdb/plugins/encryption-crypto-js'); the faster lane is the Premium web-crypto encryption plugin, which is part of the paid Premium package. The same article covers key compression — keyCompression: true in the schema — which shrinks stored field names at the cost of slightly less human-readable storage. The beginner's rule of thumb: prototype unencrypted, then turn on encryption before real user data touches the database, because encrypting an existing plaintext store is a migration you do not want to do twice.
When Should You Graduate From RxDB to a Server Database?
You graduate from RxDB to a server database when the app's center of gravity moves off the device — and saying that line once is the honest ending to a local-first guide. RxDB is the right home for per-user data, offline-capable apps, caches, and client state that syncs occasionally. It stops being the right home when you need server-side authority (leaderboards, financial ledgers, multi-user conflict arbitration), heavy analytics over everyone's data, or queries that no client should be able to run. The graduation path is not "throw RxDB away" — most graduated architectures keep RxDB on the client and add a real server behind the replication handlers. When that server needs a home, our what is VPS hosting explainer covers the hosting side, and a Postgres instance behind those replication endpoints is the natural first choice. Keep RxDB where it wins: on the device, instant, offline, reactive.
What Are the 7 Mistakes Every RxDB Beginner Makes?
The table below is an original citable asset for this guide — seven mistakes assembled from the official docs' warnings and the caution lines in RxDB's own framework articles, each paired with the fix.
| Mistake | Why it hurts | The fix |
|---|---|---|
| Copying pre-v15 snippets | RxDB.create and websql adapters no longer exist | Only trust imports from 'rxdb/plugins/*' |
| Shipping dev-mode to production | Validation overhead in a production bundle | Gate addRxPlugin(RxDBDevModePlugin) behind your dev build |
| Forgetting maxLength on the primary key | Schema validation fails on first insert | Every primary-key field declares maxLength |
| Encrypting a field you query on | Encrypted fields cannot be queried directly | Encrypt payload fields, index plaintext ones |
| Expecting a server push for "realtime" | Waiting on a backend that was never required | Realtime here is local reactivity plus optional replication |
| Using LocalStorage in Node.js | ReferenceError: localStorage is not defined | Use Dexie, SQLite, or FoundationDB on the server |
| Skipping the storage decision | Wrong persistence baked in from day one | Pick storage deliberately: prototype free, produce on SQLite |
Sources
- pubkey/rxdb GitHub repository README — tagline "the local-first database that runs on every JS runtime and replicates with your existing backend — no vendor, no lock-in", headline "A fast, local-first, reactive Database for JavaScript Applications", 23,424 stars / 1,183 forks / Apache-2.0 license (snapshot fetched November 2, 2026; counts move)
- Official RxDB quickstart — npm install rxdb rxjs; 'rxdb/plugins/*' import layout; createRxDatabase; addCollections; insert/find/exec/patch/remove; observable queries; replicateHTTP (rxdb.info/quickstart.html, fetched November 2, 2026)
- RxDB Angular + IndexedDB article by Daniel Meyer (updated October 19, 2026) — zone-patch-rxjs, $ Signal accessor with RxReactivityFactory and toSignal, indexes, premium IndexedDB storage (rxdb.info/articles/angular-indexeddb.html, fetched November 2, 2026)
- RxDB Ionic storage article by Daniel Meyer (updated October 19, 2026) — local-first, AES field encryption with encrypted schema fields, keyCompression, LocalStorage-to-Premium-SQLite path, crypto-js plugin (rxdb.info/articles/ionic-storage.html, fetched November 2, 2026)
- RxDB Node.js database guide — FoundationDB storage with apiVersion and clusterFile, SQLite faster but vertical-only, ~4 GB Node memory default, no localStorage in Node, SQLite trial 500-document limit (rxdb.info/nodejs-database.html, fetched November 2, 2026)
- npm registry — rxdb package version 17.6.0 (verified November 2, 2026; versions move, check npm for the latest)
Frequently Asked Questions
Is RxDB free to use?
Yes — RxDB Core is Apache 2.0 licensed and free, including the Dexie, LocalStorage, in-memory, FoundationDB, and SQLite-trial storages. The paid lane is the Premium package: the full SQLite storage, the premium IndexedDB storage, the memory-mapped storage, and the web-crypto encryption plugin all require buying Premium access, per the official Node.js docs.
Is RxDB a replacement for Firebase or Supabase?
Not directly. Firebase and Supabase are backend platforms; RxDB is a client-side database that can replicate to many backends, including Supabase and Firestore, via its replication plugins. Think of RxDB as the database inside your app and the backend as the optional sync target — the two compose rather than compete.
Does RxDB work offline?
Yes — that is the local-first point. Reads and writes hit the local storage first, so the app works fully offline, and replication syncs with the backend when the network returns. The Ionic article frames it exactly this way: data stored locally, offline-capable, auto-sync on reconnect.
Which storage should a beginner start with?
Start with Dexie (IndexedDB) for browser apps — it is free, persistent, and the default pick. Prototype on LocalStorage if you want zero setup friction, and move to the Premium SQLite storage for production mobile apps, following the path RxDB's own Ionic article recommends.
Do I need a backend to use RxDB?
No. Replication is an optional plugin, not a requirement — the database is fully functional local-first. You add replicateHTTP (or another replication plugin) only when you want the local data to sync with a server, and the sync protocol needs just three simple HTTP endpoints on your side.