rxdb
A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
Top Related Projects
:kangaroo: - PouchDB is a pocket-sized database.
Realm is a mobile database: an alternative to SQLite & key-value stores
Simple and fast JSON database
The JavaScript Database, for Node.js, nw.js, electron and the browser
💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.
A Minimalistic Wrapper for IndexedDB
Quick Overview
RxDB is a reactive, offline-first, and cross-platform database for JavaScript applications. It provides a powerful and flexible data management solution that integrates seamlessly with reactive programming patterns, making it well-suited for building modern, responsive web and mobile applications.
Pros
- Reactive Data Management: RxDB leverages the power of RxJS observables, allowing developers to easily manage and react to changes in their application's data.
- Offline-First Capabilities: RxDB supports offline-first functionality, enabling applications to work even when the user is disconnected from the internet.
- Cross-Platform Compatibility: RxDB can be used in a variety of JavaScript environments, including web browsers, Node.js, and React Native.
- Extensive Ecosystem: The RxDB project has a rich ecosystem, with a wide range of plugins and integrations available to extend its functionality.
Cons
- Steep Learning Curve: Developers new to reactive programming and RxJS may find the initial setup and learning curve for RxDB to be challenging.
- Performance Overhead: The reactive nature of RxDB can introduce some performance overhead, especially for large datasets or complex queries.
- Limited Documentation: While the RxDB documentation is generally good, some areas may lack detailed explanations or examples, making it harder for newcomers to get started.
- Dependency on RxJS: RxDB is tightly coupled with the RxJS library, which may be a concern for developers who prefer to use a different reactive programming library.
Code Examples
Creating a RxDB Database
import { createRxDatabase, addRxPlugin } from 'rxdb';
import { getRxStoragePouch } from 'rxdb/plugins/pouchdb';
// Add the PouchDB plugin
addRxPlugin(getRxStoragePouch());
// Create a new RxDB database
const db = await createRxDatabase({
name: 'myapp',
storage: getRxStoragePouch('idb')
});
Defining a RxDB Collection
const userCollection = await db.addCollection({
name: 'users',
schema: {
title: 'user',
version: 0,
type: 'object',
properties: {
name: { type: 'string' },
email: { type: 'string' },
age: { type: 'number' }
}
}
});
Inserting and Querying Data
// Insert a new user document
await userCollection.insert({
name: 'John Doe',
email: 'john@example.com',
age: 30
});
// Query for users older than 25
const olderUsers = await userCollection.find({
selector: { age: { $gt: 25 } }
}).exec();
Subscribing to Data Changes
// Subscribe to changes in the user collection
const userChanges$ = userCollection.$.subscribe((users) => {
console.log('Users updated:', users);
});
Getting Started
To get started with RxDB, follow these steps:
- Install the RxDB package:
npm install rxdb
- Import the necessary RxDB modules and create a new database:
import { createRxDatabase, addRxPlugin } from 'rxdb';
import { getRxStoragePouch } from 'rxdb/plugins/pouchdb';
addRxPlugin(getRxStoragePouch());
const db = await createRxDatabase({
name: 'myapp',
storage: getRxStoragePouch('idb')
});
- Define a new collection and insert some data:
const userCollection = await db.addCollection({
name: 'users',
schema: {
// Define the schema for the user collection
}
});
await userCollection.insert({
name: 'John Doe',
email: 'john@example.com',
age: 30
});
- Subscribe to changes in the user collection:
const userChanges$ = userCollection.$.subscribe((
Competitor Comparisons
:kangaroo: - PouchDB is a pocket-sized database.
Pros of PouchDB
- Mature and widely adopted, with a large community and extensive documentation
- Native support for CouchDB synchronization
- Supports multiple storage backends (IndexedDB, WebSQL, LevelDB)
Cons of PouchDB
- Limited query capabilities compared to RxDB's RxQuery
- Lacks built-in reactive programming features
- Performance can be slower for complex operations and large datasets
Code Comparison
PouchDB
const db = new PouchDB('mydb');
db.put({
_id: 'mydoc',
title: 'Hello PouchDB'
}).then(function (response) {
// Handle response
}).catch(function (err) {
console.log(err);
});
RxDB
const db = await createRxDatabase({
name: 'mydb',
adapter: 'idb'
});
const myCollection = await db.addCollection({
name: 'mycollection',
schema: mySchema
});
await myCollection.insert({
title: 'Hello RxDB'
});
RxDB offers a more structured approach with schema validation and reactive programming support, while PouchDB provides a simpler API with built-in CouchDB synchronization. RxDB's query system is more powerful, but PouchDB has broader storage backend support and a larger ecosystem.
Realm is a mobile database: an alternative to SQLite & key-value stores
Pros of Realm
- Native mobile performance with optimized C++ core
- Robust synchronization capabilities for offline-first apps
- Strong ecosystem and corporate backing (MongoDB)
Cons of Realm
- Steeper learning curve due to unique object model
- Less flexibility in data modeling compared to RxDB
- Limited support for web applications
Code Comparison
Realm:
const realm = await Realm.open({
schema: [{ name: 'Person', properties: { name: 'string', age: 'int' } }]
});
realm.write(() => {
realm.create('Person', { name: 'John', age: 30 });
});
RxDB:
const db = await createRxDatabase({
name: 'mydb',
storage: getRxStorageDexie()
});
await db.addCollections({
persons: {
schema: {
type: 'object',
properties: { name: { type: 'string' }, age: { type: 'integer' } }
}
}
});
await db.persons.insert({ name: 'John', age: 30 });
Both Realm and RxDB offer offline-first database solutions for JavaScript applications, but they cater to different use cases. Realm excels in native mobile development with its performance-optimized core and robust synchronization features. It benefits from strong corporate backing and a mature ecosystem. However, Realm has a steeper learning curve due to its unique object model and is less flexible in data modeling compared to RxDB. RxDB, on the other hand, provides more flexibility and is better suited for web applications, but may not match Realm's native mobile performance.
Simple and fast JSON database
Pros of lowdb
- Lightweight and simple to use, with a minimal API
- Supports synchronous operations, making it easier for small projects
- No dependencies, resulting in a smaller package size
Cons of lowdb
- Limited querying capabilities compared to RxDB's advanced querying
- Lacks real-time synchronization and multi-tab support
- No built-in encryption or data validation features
Code Comparison
lowdb:
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync('db.json')
const db = low(adapter)
db.defaults({ posts: [] }).write()
db.get('posts').push({ id: 1, title: 'lowdb is easy' }).write()
RxDB:
import { createRxDatabase } from 'rxdb';
const db = await createRxDatabase({
name: 'mydb',
adapter: 'idb'
});
await db.addCollections({
posts: {
schema: {
title: 'post',
version: 0,
properties: { id: { type: 'string' }, title: { type: 'string' } }
}
}
});
await db.posts.insert({ id: '1', title: 'RxDB is powerful' });
The JavaScript Database, for Node.js, nw.js, electron and the browser
Pros of NeDB
- Lightweight and easy to set up, with no external dependencies
- Supports in-memory and persistent storage options
- Familiar MongoDB-like API for easy adoption
Cons of NeDB
- Limited scalability for large datasets
- Lack of real-time synchronization features
- No built-in encryption or advanced security features
Code Comparison
NeDB:
const Datastore = require('nedb');
const db = new Datastore({ filename: 'path/to/datafile', autoload: true });
db.insert({ name: 'John', age: 30 }, (err, newDoc) => {
// Handle insertion
});
RxDB:
const { createRxDatabase } = require('rxdb');
const db = await createRxDatabase({
name: 'mydb',
adapter: 'idb'
});
const collection = await db.addCollection({
name: 'users',
schema: mySchema
});
await collection.insert({ name: 'John', age: 30 });
Key Differences
- RxDB offers real-time synchronization and offline-first capabilities
- NeDB is more suitable for simple, lightweight applications
- RxDB provides a reactive programming model with observables
- NeDB has a simpler API, while RxDB offers more advanced features
- RxDB supports multiple adapters for various storage options
💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.
Pros of localForage
- Simpler API and easier to use for basic storage needs
- Broader browser support, including older versions
- Smaller bundle size, suitable for lightweight applications
Cons of localForage
- Limited querying capabilities compared to RxDB's advanced query options
- Lacks real-time capabilities and reactive data handling
- No built-in support for data replication or sync
Code Comparison
localForage:
await localForage.setItem('key', value);
const storedValue = await localForage.getItem('key');
RxDB:
const doc = await collection.insert({ id: 'key', value: value });
const storedValue = await collection.findOne('key').exec();
Key Differences
- RxDB offers a more robust database-like structure with collections and documents
- localForage provides a simple key-value storage API
- RxDB includes features like real-time updates, data replication, and advanced querying
- localForage focuses on providing a unified API across different storage backends
Use Cases
- localForage: Ideal for simple storage needs in web applications, especially when broad browser support is required
- RxDB: Better suited for complex applications requiring real-time data, offline-first capabilities, and advanced data management features
Both libraries serve different purposes, with localForage being a lightweight solution for basic storage, while RxDB offers a more comprehensive database system for web and mobile applications.
A Minimalistic Wrapper for IndexedDB
Pros of Dexie.js
- Simpler API and easier learning curve for developers familiar with JavaScript
- Lightweight and focused specifically on IndexedDB wrapper functionality
- Better performance for basic CRUD operations and simple queries
Cons of Dexie.js
- Lacks built-in real-time synchronization capabilities
- Limited support for complex querying and data relationships compared to RxDB
- No out-of-the-box offline-first or multi-tab synchronization features
Code Comparison
Dexie.js:
const db = new Dexie('MyDatabase');
db.version(1).stores({
friends: '++id, name, age'
});
await db.friends.add({ name: 'John', age: 30 });
const youngFriends = await db.friends.where('age').below(35).toArray();
RxDB:
const db = await createRxDatabase({
name: 'mydb',
storage: getRxStorageDexie()
});
await db.addCollections({
friends: {
schema: mySchema
}
});
await db.friends.insert({ name: 'John', age: 30 });
const youngFriends = await db.friends.find({ selector: { age: { $lt: 35 } } }).exec();
Both libraries provide easy-to-use APIs for working with IndexedDB, but RxDB offers more advanced features like real-time synchronization and offline-first capabilities at the cost of a steeper learning curve and potentially lower performance for simple operations.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
A fast, local-first, reactive Database for JavaScript Applications
What is RxDB?
RxDB (short for Reactive Database) is a local-first, NoSQL-database for JavaScript Applications like Websites, hybrid Apps, Electron-Apps, Progressive Web Apps, Deno and Node.js.
Reactive means that 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.
This is great for UI-based realtime applications in a way that makes it easy to develop and also has great performance benefits but can also be used to create fast backends in Node.js.
RxDB provides an easy to implement protocol for realtime replication with your existing infrastructure or one of the plugins for HTTP, GraphQL, CouchDB, Websocket, WebRTC, Supabase, Firestore, NATS.
RxDB is based on a storage interface that enables you to swap out the underlying storage engine. This increases code reuse because you can use the same database code for different JavaScript environments by just switching out the storage settings.
Use the quickstart, read the documentation or explore the example projects.
Multiplayer realtime applications
Replicate with your existing infrastructure
RxDB provides an easy to implement, battle-tested replication protocol for realtime sync with your existing infrastructure.
There are also plugins to easily replicate with GraphQL, CouchDB, Websocket, WebRTC,Supabase, Firestore or NATS.
Flexible storage layer
RxDB is based on a storage interface that enables you to swap out the underlying storage engine. This increases code reuse because the same database code can be used in different JavaScript environments by just switching out the storage settings.
You can use RxDB on top of IndexedDB, OPFS, LokiJS, Dexie.js, in-memory, SQLite, in a WebWorker thread and even on top of FoundationDB and DenoKV.
No matter what kind of runtime you have, as long as it runs JavaScript, it can run RxDB:
Browsers Node.js React Native Capacitor NativeScript Flutter or as an Electron Database
Quick start
Install
npm install rxdb rxjs --save
Store data
import {
createRxDatabase
} from 'rxdb/plugins/core';
/**
* For browsers, we use the dexie.js based storage
* which stores data in IndexedDB in the browser.
* In other JavaScript runtimes, we can use different storages:
* @link https://rxdb.info/rx-storage.html
*/
import { getRxStorageDexie } from 'rxdb/plugins/storage-dexie';
// create a database
const db = await createRxDatabase({
name: 'heroesdb', // the name of the database
storage: getRxStorageDexie()
});
// add collections
await db.addCollections({
heroes: {
schema: mySchema
}
});
// insert a document
await db.heroes.insert({
name: 'Bob',
healthpoints: 100
});
Query data once
const aliveHeroes = await db.heroes.find({
selector: {
healthpoints: {
$gt: 0
}
}
}).exec(); // the exec() returns the result once
Observe a Query
await db.heroes.find({
selector: {
healthpoints: {
$gt: 0
}
}
})
.$ // the $ returns an observable that emits each time the result set of the query changes
.subscribe(aliveHeroes => console.dir(aliveHeroes));
Continue with the quickstart here.
More Features (click to toggle)
Subscribe to events, query results, documents and event single fields of a document
RxDB implements rxjs to make your data reactive.
This makes it easy to always show the real-time database-state in the dom without manually re-submitting your queries.
You can also add custom reactiveness libraries like signals or other state management.
db.heroes
.find()
.sort('name')
.$ // <- returns observable of query
.subscribe( docs => {
myDomElement.innerHTML = docs
.map(doc => '<li>' + doc.name + '</li>')
.join();
});
MultiWindow/Tab
RxDB supports multi tab/window usage out of the box. When data is changed at one browser tab/window or Node.js process, the change will automatically be broadcasted to all other tabs so that they can update the UI properly.
EventReduce
One big benefit of having a realtime database is that big performance optimizations can be done when the database knows a query is observed and the updated results are needed continuously. RxDB internally uses the Event-Reduce algorithm. This makes sure that when you update/insert/remove documents,
the query does not have to re-run over the whole database but the new results will be calculated from the events. This creates a huge performance-gain
with zero cost.
Use-Case-Example
Imagine you have a very big collection with many user-documents. At your page you want to display a toplist with users which have the most points
and are currently logged in.
You create a query and subscribe to it.
const query = usersCollection.find().where('loggedIn').eq(true).sort('points');
query.$.subscribe(users => {
document.querySelector('body').innerHTML = users
.reduce((prev, cur) => prev + cur.username+ '<br/>', '');
});
As you may detect, the query can take very long time to run, because you have thousands of users in the collection. When a user now logs off, the whole query will re-run over the database which takes again very long.
await anyUser.incrementalPatch({loggedIn: false});
But not with the EventReduce.
Now, when one user logs off, it will calculate the new results from the current results plus the RxChangeEvent. This often can be done in-memory without making IO-requests to the storage-engine. EventReduce not only works on subscribed queries, but also when you do multiple .exec()
's on the same query.
Schema
Schemas are defined via jsonschema and are used to describe your data.
const mySchema = {
title: "hero schema",
version: 0, // <- incremental version-number
description: "describes a simple hero",
primaryKey: 'name', // <- 'name' is the primary key for the collection, it must be unique, required and of the type string
type: "object",
properties: {
name: {
type: "string",
maxLength: 30
},
secret: {
type: "string",
},
skills: {
type: "array",
maxItems: 5,
uniqueItems: true,
item: {
type: "object",
properties: {
name: {
type: "string"
},
damage: {
type: "number"
}
}
}
}
},
required: ["color"],
encrypted: ["secret"] // <- this means that the value of this field is stored encrypted
};
Mango / Chained queries
RxDB can be queried by standard NoSQL mango queries like you maybe know from other NoSQL Databases like mongoDB.
Also you can use the query-builder plugin to create chained mango-queries.
// normal query
myCollection.find({
selector: {
name: {
$ne: 'Alice'
},
age: {
$gt: 67
}
},
sort: [{ age: 'desc' }],
limit: 10
})
// chained query
myCollection
.find()
.where('name').ne('Alice')
.where('age').gt(18).lt(67)
.limit(10)
.sort('-age')
.exec().then( docs => {
console.dir(docs);
});
Encryption
By setting a schema-field to encrypted
, the value of this field will be stored in encryption-mode and can't be read without the password. Of course you can also encrypt nested objects. Example:
encrypted
, the value of this field will be stored in encryption-mode and can't be read without the password. Of course you can also encrypt nested objects. Example:{
"title": "my schema",
"properties": {
"secret": {
"type": "string",
"encrypted": true
}
},
"encrypted": [
"secret"
]
}
Import / Export
RxDB lets you import and export the whole database or single collections into json-objects. This is helpful to trace bugs in your application or to move to a given state in your tests.
// export a single collection
const jsonCol = await myCollection.dump();
// export the whole database
const jsonDB = await myDatabase.dump();
// import the dump to the collection
await emptyCollection.importDump(json);
// import the dump to the database
await emptyDatabase.importDump(json);
Key-Compression
Depending on which adapter and in which environment you use RxDB, client-side storage is limited in some way or the other. To save disc-space, RxDB uses a schema based keycompression to minimize the size of saved documents. This saves about 40% of used storage.
Example:
// when you save an object with big keys
await myCollection.insert({
firstName: 'foo'
lastName: 'bar'
stupidLongKey: 5
});
// key compression will internally transform it to
{
'|a': 'foo'
'|b': 'bar'
'|c': 5
}
// so instead of 46 chars, the compressed-version has only 28
// the compression works internally, so you can of course still access values via the original key.names and run normal queries.
console.log(myDoc.firstName);
// 'foo'
And for any other use case, there are many more plugins and addons.
Get started
Get started now by reading the docs or exploring the example-projects.
Support and Contribute
- Check out how you can contribute to this project.
- Read this when you have found a bug
- Buy access to the premium plugins
- Join us at discord to get help
- Give Feedback (anonymous)
More content
Angular Database, Frontend Database, localStorage, React Database, Browser Database, React Native Database, PWA Database, In-memory NoSQL database, JSON database
Top Related Projects
:kangaroo: - PouchDB is a pocket-sized database.
Realm is a mobile database: an alternative to SQLite & key-value stores
Simple and fast JSON database
The JavaScript Database, for Node.js, nw.js, electron and the browser
💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.
A Minimalistic Wrapper for IndexedDB
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot