# RxDB: a local-first database you can point at whatever backend you already run

> A reactive NoSQL database for JavaScript that treats the storage engine as a swappable detail and reaches your server over three HTTP endpoints instead of demanding its own cloud.

**pubkey/rxdb** — The local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/

- Repository: https://github.com/pubkey/rxdb
- Website: https://rxdb.info/
- Stars: 23,406 · Forks: 1,176
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/pubkey-rxdb

## Reactive means the query result is the subscription

RxDB expands to Reactive Database, and the reactivity is the part that distinguishes it from a thin wrapper over IndexedDB. The README puts it plainly: you can not only query the current state, but subscribe to all state changes like the result of a query or even a single field of a document. That is a narrower and more useful claim than it first sounds. You are not subscribing to a generic change stream and then filtering it yourself. You run the query you already wrote, and the emitted value is a fresh result set for that query.

For a UI this removes a specific class of code. The usual hand-rolled pattern is a component that queries on mount, subscribes to a change feed, filters the feed down to the rows it cares about, and re-queries when a filter matches. With a reactive query, the filter lives in the query. The project frames this as good for realtime applications in a way that makes it easy to develop, and the performance argument is that the filtering happens closer to the data rather than in your event handler.

The npm keywords reflect that positioning rather than a generic database taxonomy. Alongside the obvious entries like `nosql`, `jsonschema` and `indexeddb`, the list includes `live-query`, `realtime query`, `reactive` and `database abstraction layer`, which tells you the package is competing partly on the query layer and partly on portability. Version 17.5.0 declares `sideEffects` as false and ships both a CommonJS entry at `./dist/cjs/index.js` and types at `./dist/types/index.d.ts`, so it is a normal ESM-ready library dependency rather than a runtime shim you have to configure.

## The storage interface is the actual architecture

The README's most consequential claim is that RxDB sits on a storage interface, which enables you to swap out the underlying storage engine, and that this increases code reuse because the same database code can be used in different JavaScript environments by just switching out the storage settings. The listed engines span a wide range: LocalStorage, IndexedDB, OPFS, LokiJS, Dexie.js, in-memory, SQLite, a WebWorker thread, and even FoundationDB and DenoKV.

That list is worth reading as two tiers. The browser entries (LocalStorage, IndexedDB, OPFS, in-memory) are the ones a front-end developer will pick between, and they are not interchangeable in practice. LocalStorage is synchronous and tiny, IndexedDB is the general browser default, OPFS is the newer origin-private file system with a much larger storage budget, and Dexie.js is a third-party IndexedDB wrapper with its own ergonomics. RxDB does not pretend these are the same thing; it defines one interface they each satisfy, which means your collection definitions and query code survive the swap.

The server-side and hybrid entries (SQLite, FoundationDB, DenoKV, WebWorker) widen the range further. A WebWorker storage engine in particular addresses a real problem: doing database work on the main thread is where browser apps lose responsiveness. Pointing the storage at a worker keeps the same API while moving the work off the UI thread.

```json
"engines": {
    "node": ">=20"
  },
  "license": "Apache-2.0",
  "types": "./dist/types/index.d.ts",
  "sideEffects": false,
  "main": "./dist/cjs/index.js",
```

The runtime claim follows from that design: no matter what kind of runtime you have, as long as it runs JavaScript, it can run RxDB. The README names browsers, Node.js, React Native and Capacitor, and the `examples/` directory backs that up with angular, electron, flutter, graphql, ionic, node, react-native, react, supabase, svelte, tauri, vite-vanilla-ts and vue. Thirteen runnable targets is a much stronger argument for the portability claim than a bullet list of supported platforms would be. Note that Node 20 is the declared floor, which is worth checking against your runtime before you start.

## Replication is three HTTP endpoints, not a vendor

This is where RxDB parts company with hosted client databases. The README states you do not have to use a specific cloud or backend database, and that the protocol works by implementing three simple HTTP endpoints. Three endpoints is a small enough contract that you can implement it against a database you already run, in a language you already write, without adopting anything new on the server.

There are also production-ready plugins for the cases where writing those endpoints yourself is not worth the time: GraphQL, CouchDB, Websocket, WebRTC for peer-to-peer, Supabase, Firestore, NATS and Google Drive. The Google Drive and WebRTC entries are the interesting ones, because they are replication targets nobody would design a hosted backend around. They exist precisely because the underlying protocol is backend-neutral.

The plugin list is also a decent map of the database landscape RxDB wants to coexist with. PouchDB, CouchDB and Firestore are document stores, Supabase is Postgres-shaped, NATS is messaging, Websocket is a transport. If you are weighing RxDB against PouchDB specifically, the relevant comparison is not query syntax but sync semantics, and PouchDB is the more opinionated of the two about its replication model.

Two releases in 2026 show what operating the sync layer actually involves. The 17.4.0 release added `replicationState.awaitDocumentPushed(rxDocument)`, which returns a promise that resolves once the given RxDocument state was successfully pushed to the server, plus a `replicationState.conflict$` observable that emits each conflict reported by the remote in the response of the push handler. Both came out of issue 8632, which was about that promise resolving despite a conflict that was later resolved. In other words, the questions you would want answered about replication reliability were surfaced as real bugs and answered with new API surface. The 17.3.0 release went further and expanded the partial sync documentation to cover multiple `replicateRxCollection` states, per-scope checkpoints, document tagging via `pull.modifier` and `push.modifier`, scope cleanup, realtime pull streams and tradeoffs.

## What the repository signals say about adoption

GitHub reports roughly 23,400 stars, about 1,175 forks and 17 open issues for the repository, under Apache-2.0, with TypeScript as the primary language and a last push on 2026-09-18. The repository is not archived and `master` is the default branch.

A low open-issue count alongside that star count is the signal worth pausing on. It means either that the maintainer is responsive, which the release cadence supports, or that issues are handled elsewhere, which for a library with a Discord link and a dedicated documentation site is plausible. Either way, the practical consequence for you is that this is not a repository where you should expect to diagnose your own problem in public threads.

The repository topics place it precisely: local-first, indexeddb, crdt, sqlite, pouchdb, graphql, react-native, realtime, browser-database, localstorage, firebase, postgres, couchdb. Read that list as a compatibility declaration rather than a feature list. A `crdt` topic is worth flagging on its own, because the README's storage enumeration says nothing about conflict-free replicated data types. Either that work is documented elsewhere on rxdb.info, or the topic is aspirational tagging. Neither reading damages the project, and both are reasons to read the replication documentation rather than assume conflict semantics from a topic label.

The tree also shows how documentation-heavy the project is. Beyond `src/`, `test/` and `config/`, there is a `docs-src/` directory, an `orga/` directory whose purpose is not evident from the name alone, both `AGENTS.md` and `CLAUDE.md` at the root, and `renovate.json` for dependency updates. The presence of agent instruction files at the root is a recent and telling convention: it means the project expects automated tooling to work on it, and it fits a repository that keeps a large documentation site in the same tree as the library.

## Where RxDB is the wrong choice

Local-first is a design commitment, not a feature toggle, and it pays off only if your application actually runs offline, across devices, or with multiple writers. If your app is a thin client that talks to one server and always has connectivity, a reactive local database adds a cache you must keep consistent with a source of truth you already have. The replication layer becomes a second thing that can be wrong.

Second, the client owns the schema. That is inherent to local-first design: a device holding a year of local data must be able to read it with the code it is running, which means migration logic lives in your application and has to work for versions of your app that users have not upgraded yet. The `migrate database` keyword in `package.json` is a reminder that this is a first-class concern rather than a detail.

Third, eventual consistency is not free to reason about. The 17.4.0 additions of `awaitDocumentPushed()` and `conflict$` exist because knowing whether a write has landed, and knowing what the server rejected, are non-trivial questions. A UI that must never show unconfirmed state needs those APIs plus a conflict resolution policy, and that policy is yours to write.

Finally, the README is a shop window, not a manual. It gives you the architecture, the storage options, the replication targets and three links: the quickstart, the documentation and the example projects. Everything about encryption, multi-instance tab coordination, attachment handling and migration strategy is one hop away on rxdb.info. Judge the project on that documentation, because that is where you will live.

## Conclusion

RxDB is at its best when the client is the first-class place data lives, which is the common shape of an offline-capable or multiplayer app. The reactive query model means a component subscribes to the data it renders instead of managing subscriptions and cache invalidation by hand, the storage interface means the same collection code can start on IndexedDB and move to SQLite or OPFS, and the three-endpoint replication protocol means the server side does not have to be a database vendor. The cost is real: you own schema migration on clients you cannot force-update, replication is eventually consistent, and the security and conflict story lives in the documentation rather than the README. GitHub reports the last push on 2026-09-18 with 17.5.0 shipped 2026-08-20, so the line is moving while you read this. Read the replication protocol and the storage interface pages, then build one collection end to end before committing a schema across your installed base.

## FAQ

### What are some alternatives to IndexedDB?

The usual shortlist is Dexie.js, an IndexedDB wrapper with typings and versioning; PouchDB, a document store with CouchDB-style replication built in; LokiJS, an in-memory store with optional persistence; OPFS, the browser origin-private file system, which is a storage primitive rather than a database; and SQLite compiled to WebAssembly. RxDB sits across these rather than beside them, because it is a query and replication layer that treats IndexedDB, Dexie.js, LokiJS, OPFS and SQLite as interchangeable storage engines. The useful comparison is therefore RxDB against PouchDB or against a thin Dexie.js wrapper, not RxDB against any single engine.

### Is RxDB still actively maintained?

GitHub reports the last push on 2026-09-18 and three releases in 2026: 17.3.0 on 2026-05-28, 17.4.0 on 2026-07-13 and 17.5.0 on 2026-08-20. Those releases contain real work rather than dependency bumps, including a fix allowing preInsert hooks to set composite primary key fields and new replication APIs for awaiting a push and observing conflicts. The repository is not archived, and `renovate.json` at the root handles automated dependency updates.

### How does RxDB compare with PouchDB for replication?

Both are local-first document databases for JavaScript, and both reach a remote without requiring a hosted vendor. The difference is that PouchDB is opinionated about the replication protocol and is built around the CouchDB model, while RxDB defines a replication protocol of three simple HTTP endpoints and then ships plugins for CouchDB, GraphQL, Supabase, Firestore, NATS, Websocket, WebRTC and Google Drive. If your remote is CouchDB and you want the shortest path, PouchDB is the closer fit. If your remote is something else you already run, RxDB is the closer fit.

### Can RxDB run in Node.js or React Native, not just a browser?

Yes, and this is the part of the design that holds up best on inspection. Because RxDB is built on a storage interface, the same collection and query code runs against a different engine per runtime: IndexedDB or OPFS or Dexie.js in a browser, SQLite or DenoKV or FoundationDB on a server, in-memory in a test. The repository's `examples/` directory contains runnable projects for node, react-native, electron, flutter, tauri and the major frontend frameworks. The one constraint to check first is the declared engine floor in `package.json`, which requires Node 20 or newer.

### Does RxDB require its own backend or cloud account?

No. The README is explicit that you do not have to use a specific cloud or backend database, because the sync protocol works by implementing three simple HTTP endpoints on your side. That is the main argument against the objection that local-first forces a vendor choice, since you can implement those endpoints against a database and language you already operate. If you would rather not write them, the production-ready plugins for GraphQL, CouchDB, Supabase, Firestore, NATS, Websocket, WebRTC and Google Drive cover the common cases.

## Sources

- [License: Apache-2.0](https://github.com/pubkey/rxdb/blob/master/LICENSE)
- [Project website](https://rxdb.info/)
- [pubkey/rxdb on GitHub](https://github.com/pubkey/rxdb)
- [README](https://github.com/pubkey/rxdb/blob/master/README.md)
- [Releases](https://github.com/pubkey/rxdb/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pubkey-rxdb
