RxDB: Local-First Reactive Database
raw JSON →RxDB is a local-first, NoSQL database designed for JavaScript applications, supporting environments like websites, hybrid apps, Electron, PWAs, Deno, and Node.js. It operates on a reactive paradigm, built on RxJS, allowing developers to subscribe to real-time state changes for queries, documents, or individual fields, which simplifies UI development for real-time applications and enhances performance. The package is currently at version 15.36.1, with major releases occurring periodically, as seen with the recent version 15.0.0. Key differentiators include its local-first approach, robust JSON schema validation, and a flexible replication protocol that integrates with existing infrastructure or plugins for HTTP, GraphQL, and CouchDB, making it suitable for offline-first capabilities.
Common errors
error Error: Cannot find module 'test-rxdb/plugins/storage-dexie' ↓
npm install rxdb-storage-dexie and import from it: import { getRxStorageDexie } from 'rxdb-storage-dexie'; error TypeError: (0 , test_rxdb__WEBPACK_IMPORTED_MODULE_0__.createRxDatabase) is not a function ↓
import { createRxDatabase } from 'test-rxdb'; and confirm your bundler/Node.js environment correctly processes ESM files. error RxError: MvRx_NoRxStorageFound: Cannot create database, no storage set ↓
storage option when creating your database, e.g., createRxDatabase({ name: 'mydb', storage: getRxStorageDexie() }). error RxError: UT8: Crypto.subtle.digest is not available in your runtime. ↓
crypto.subtle or provide a custom hash function to RxDB. Warnings
breaking RxDB v15+ is distributed as pure ES Modules (ESM). Projects using CommonJS (`require()`) must adapt their build setup (e.g., using a bundler with ESM support or configuring Node.js with `"type": "module"`). ↓
breaking The storage API was completely rewritten in v15. Storage adapters must now be explicitly imported and passed to `createRxDatabase()` via the `storage` option. The old `storage.js` plugin and implicit storage handling are removed. ↓
breaking RxDB v15 no longer bundles `node:crypto` in browser builds. If your application relies on crypto functionalities (e.g., hashing), you might need to provide a polyfill for browser environments. ↓
gotcha RxDB has a peer dependency on RxJS (`^7.8.0`). Ensure you have a compatible version of RxJS installed, as mismatches can lead to runtime errors or unexpected behavior. ↓
deprecated The `LokiJS RxStorage` was deprecated in RxDB v15 and completely removed in v16, as the LokiJS library is no longer actively maintained. ↓
breaking The `.destroy()` method has been renamed to `.close()` in RxDB v16 to better reflect its function of closing the database connection without deleting data. ↓
Install
npm install test-rxdb yarn add test-rxdb pnpm add test-rxdb Imports
- createRxDatabase wrong
const createRxDatabase = require('test-rxdb').createRxDatabase;correctimport { createRxDatabase } from 'test-rxdb'; - addRxPlugin wrong
const addRxPlugin = require('test-rxdb').addRxPlugin;correctimport { addRxPlugin } from 'test-rxdb'; - getRxStorageDexie wrong
import { getRxStorageDexie } from 'test-rxdb';correctimport { getRxStorageDexie } from 'test-rxdb/plugins/storage-dexie'; - RxDatabase
import { RxDatabase, RxCollection, RxJsonSchema } from 'test-rxdb';
Quickstart
import { createRxDatabase, addRxPlugin, RxDatabase, RxCollection, RxJsonSchema } from 'test-rxdb';
import { getRxStorageDexie } from 'test-rxdb/plugins/storage-dexie'; // Assumed path for 'test-rxdb' package
interface HeroDocType {
name: string;
color: string;
hp: number;
maxHP: number;
}
type HeroCollection = RxCollection<HeroDocType>;
const heroSchema: RxJsonSchema<HeroDocType> = {
version: 0,
primaryKey: 'name',
type: 'object',
properties: {
name: {
type: 'string',
maxLength: 100 // Primary keys usually have a max length
},
color: {
type: 'string'
},
hp: {
type: 'number'
},
maxHP: {
type: 'number'
}
},
required: ['name', 'color', 'hp', 'maxHP']
};
async function runQuickstart() {
console.log('Creating database...');
const db: RxDatabase = await createRxDatabase({
name: 'heroesdb',
storage: getRxStorageDexie() // Using Dexie storage adapter
});
console.log('Database created:', db.name);
// Add a collection to the database
console.log('Adding hero collection...');
await db.addCollections({
heroes: {
schema: heroSchema
}
});
console.log('Hero collection added.');
const heroCollection: HeroCollection = db.collections.heroes;
// Insert documents
console.log('Inserting heroes...');
await heroCollection.insert({
name: 'Batman',
color: 'black',
hp: 100,
maxHP: 100
});
await heroCollection.insert({
name: 'Superman',
color: 'blue',
hp: 120,
maxHP: 120
});
console.log('Heroes inserted.');
// Reactive query: subscribe to changes in the collection
console.log('Subscribing to all heroes...');
const subscription = heroCollection.find().$.subscribe(heroes => {
if (heroes) {
console.log('Current heroes:', heroes.map(h => h.toJSON()));
}
});
// Update a document, which will trigger the subscription
console.log('Updating Batman...');
const batman = await heroCollection.findOne({ selector: { name: 'Batman' } }).exec();
if (batman) {
await batman.patch({ hp: 90 });
console.log('Batman updated.');
}
// Clean up after some time
setTimeout(() => {
subscription.unsubscribe();
console.log('Subscription unsubscribed.');
db.destroy(); // Close the database connection
console.log('Database destroyed (closed).');
}, 3000);
}
runQuickstart().catch(err => console.error('Quickstart failed:', err));