RxDB: Local-First Reactive Database

raw JSON →
15.36.1 verified Thu Apr 23 auth: no javascript

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.

error Error: Cannot find module 'test-rxdb/plugins/storage-dexie'
cause Attempting to import a storage adapter from an incorrect path or if the specific adapter is not included/exported by the `test-rxdb` package (or `rxdb` in general). In actual RxDB, many storages are separate npm packages.
fix
Verify the correct import path for your chosen storage adapter. For official RxDB, you might need to install a separate package like 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
cause This typically occurs when mixing CommonJS `require()` with an ESM-only library, or due to a bundler misconfiguration preventing correct ESM resolution. RxDB v15+ is pure ESM.
fix
Ensure your project is set up for ES Modules. Use 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
cause This error means `createRxDatabase` was called without providing a storage adapter, which is mandatory in RxDB v15+.
fix
Explicitly import and pass a storage adapter to the 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.
cause RxDB v15+ utilizes `crypto.subtle.digest` for hashing. This error indicates that the Web Crypto API is unavailable in the current runtime environment.
fix
If running in a browser, ensure it supports the Web Crypto API. For non-browser environments like some React Native setups or older Node.js versions, you may need to polyfill crypto.subtle or provide a custom hash function to RxDB.
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"`).
fix Migrate your project to use ES Modules or ensure your build tools (Webpack, Rollup, Parcel) are configured to handle ESM. For Node.js, ensure `"type": "module"` is set in your `package.json`.
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.
fix Remove the `storage.js` plugin and explicitly import your chosen storage adapter (e.g., `getRxStorageDexie`) and provide it to `createRxDatabase({ storage: getRxStorageDexie() })`. Storage adapters are typically in separate packages like `rxdb-storage-dexie` or within `@rxdb/premium`.
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.
fix For browser-based applications, consider adding a polyfill for the Web Crypto API if your target environments do not fully support it, or provide a custom hash function if applicable.
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.
fix Install `rxjs` explicitly: `npm install rxjs` or `yarn add rxjs`. Verify that the installed version meets RxDB's peer dependency requirements.
deprecated The `LokiJS RxStorage` was deprecated in RxDB v15 and completely removed in v16, as the LokiJS library is no longer actively maintained.
fix Migrate to a different storage adapter like Dexie.js, IndexedDB, or OPFS for browser environments, or Filesystem Node/SQLite for Node.js.
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.
fix Update all calls from `db.destroy()` to `db.close()`. Also update related functions and attributes like `onDestroy()` to `onClose()`.
npm install test-rxdb
yarn add test-rxdb
pnpm add test-rxdb

This quickstart demonstrates how to set up an RxDB database, define a schema, add a collection, insert documents, perform a reactive query, and update data using the Dexie storage adapter.

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));