docs-src/docs/quickstart.md
import {Steps} from '@site/src/components/steps'; import {TriggerEvent} from '@site/src/components/trigger-event'; import {Tabs} from '@site/src/components/tabs'; import {NavbarDropdownSyncList} from '@site/src/components/navbar-dropdowns';
<TriggerEvent type="page_quickstart" value={0.2} maxPerUser={1} primary={false} />Welcome to the RxDB Quickstart. Here we'll learn how to create a simple real-time app with the RxDB database that is able to store and query data persistently in a browser and does realtime updates to the UI on changes.
<center> <a href="https://rxdb.info/"></a>
Install the RxDB library and the RxJS dependency:
npm install rxdb rxjs
RxDB is able to run in a wide range of JavaScript runtimes like browsers, mobile apps, desktop and servers. Therefore different storage engines exist that ensure the best performance depending on where RxDB is used.
<Tabs>Use this for the simplest browser setup and very small datasets. It has a tiny bundle size and works anywhere localStorage is available, but is not optimized for large data or heavy writes.
import {
getRxStorageLocalstorage
} from 'rxdb/plugins/storage-localstorage';
let storage = getRxStorageLocalstorage();
The premium IndexedDB storage is a high-performance, browser-native storage with a smaller bundle and faster startup compared to Dexie-based IndexedDB. Recommended when you have π premium access and care about performance and bundle size.
import {
getRxStorageIndexedDB
} from 'rxdb-premium/plugins/storage-indexeddb';
let storage = getRxStorageIndexedDB();
Dexie.js is a friendly wrapper around IndexedDB and is a great default for browser apps when you don't use premium. It's reliable, works well for medium-sized datasets, and is free to use.
import {
getRxStorageDexie
} from 'rxdb/plugins/storage-dexie';
let storage = getRxStorageDexie();
SQLite is ideal for React Native, Capacitor, Electron, Node.js and other hybrid or native environments. It gives you a fast, durable database on disk. Use the π premium storage for production; a trial version exists for quick experimentation.
Premium SQLite (Node.js example)
import {
getRxStorageSQLite,
getSQLiteBasicsNode
} from 'rxdb-premium/plugins/storage-sqlite';
// Provide the sqliteBasics adapter for your runtime, e.g. Node.js, React Native, etc.
// For example in Node.js you would derive
// sqliteBasics from a sqlite3-compatible library:
import sqlite3 from 'sqlite3';
const storage = getRxStorageSQLite({
sqliteBasics: getSQLiteBasicsNode(sqlite3)
});
SQLite trial storage (Node.js, free)
import {
getRxStorageSQLiteTrial,
getSQLiteBasicsNodeNative
} from 'rxdb/plugins/storage-sqlite';
import { DatabaseSync } from 'node:sqlite';
const storage = getRxStorageSQLiteTrial({
sqliteBasics: getSQLiteBasicsNodeNative(DatabaseSync)
});
For React Native and Expo applications, the Expo Filesystem storage offers superior performance compared to SQLite and Async Storage by utilizing OPFS JSI bindings.
import {
getRxStorageExpoAsync
} from 'rxdb-premium/plugins/storage-filesystem-expo';
let storage = getRxStorageExpoAsync();
There are many more storages such as MongoDB, DenoKV, Filesystem, Memory, Memory-Mapped, FoundationDB and more. Browse the full list of storages.
</Tabs> <details> <summary>Which storage should I use?</summary> <div> RxDB provides a wide range of storages depending on your JavaScript runtime and performance needs. <ul> <li>In the Browser: Use the <a href="/rx-storage-localstorage.html">LocalStorage</a> storage for simple setup and small build size. For bigger datasets, use either the <a href="/rx-storage-dexie.html">dexie.js storage</a> (free) or the <a href="/rx-storage-indexeddb.html">IndexedDB RxStorage</a> if you have <a href="/premium/">π premium access</a> which is a bit faster and has a smaller build size.</li> <li>In <a href="/electron-database.html">Electron</a> and <a href="/react-native-database.html">React Native</a>: Use the <a href="./rx-storage-sqlite.html">SQLite RxStorage</a> if you have <a href="/premium/">π premium access</a> or the <a href="/rx-storage-sqlite.html">SQLite Trial RxStorage</a> for tryouts.</li> <li>In Capacitor: Use the <a href="/rx-storage-sqlite.html">SQLite RxStorage</a> if you have <a href="/premium/">π premium access</a>, otherwise use the <a href="/rx-storage-localstorage.html">LocalStorage</a> storage.</li> </ul></div>
When you use RxDB in development, you should always enable the dev-mode plugin, which adds helpful checks and validations, and tells you if you do something wrong.
import { addRxPlugin } from 'rxdb/plugins/core';
import { RxDBDevModePlugin } from 'rxdb/plugins/dev-mode';
addRxPlugin(RxDBDevModePlugin);
Schema validation is required when using dev-mode and recommended (but optional) in production. Wrap your storage with the AJV schema validator to ensure all documents match your schema before being saved.
import { wrappedValidateAjvStorage } from 'rxdb/plugins/validate-ajv';
storage = wrappedValidateAjvStorage({ storage });
A database is the topβlevel container in RxDB, responsible for managing collections, coordinating persistence, and providing reactive change streams.
import { createRxDatabase } from 'rxdb/plugins/core';
const myDatabase = await createRxDatabase({
name: 'mydatabase',
storage: storage
});
An RxDatabase contains RxCollections for storing and querying data. A collection is similar to an SQL table, and individual records are stored in the collection as JSON documents. An RxDatabase can have as many collections as you need. Add a collection with a schema to the database:
await myDatabase.addCollections({
// name of the collection
todos: {
// we use the JSON-schema standard
schema: {
version: 0,
primaryKey: 'id',
type: 'object',
properties: {
id: {
type: 'string',
maxLength: 100 // <- the primary key must have maxLength
},
name: {
type: 'string'
},
done: {
type: 'boolean'
},
timestamp: {
type: 'string',
format: 'date-time'
}
},
required: ['id', 'name', 'done', 'timestamp']
}
}
});
Now that we have an RxCollection we can store some documents in it.
const myDocument = await myDatabase.todos.insert({
id: 'todo1',
name: 'Learn RxDB',
done: false,
timestamp: new Date().toISOString()
});
Execute a query that returns all found documents once:
const foundDocuments = await myDatabase.todos.find({
selector: {
done: {
$eq: false
}
}
}).exec();
In the first found document, set done to true:
const firstDocument = foundDocuments[0];
await firstDocument.patch({
done: true
});
Delete the document so that it can no longer be found in queries:
await firstDocument.remove();
Subscribe to data changes so that your UI is always up-to-date with the data stored on disk. RxDB allows you to subscribe to data changes even when the change happens in another part of your application, another browser tab, or during database replication/synchronization:
const observable = myDatabase.todos.find({
selector: {
done: {
$eq: false
}
}
}).$ // get the observable via RxQuery.$;
observable.subscribe(notDoneDocs => {
console.log('Currently have ' + notDoneDocs.length + ' things to do');
// -> here you would re-render your app to show the updated document list
});
You can also subscribe to the fields of a single RxDocument. Add the $ sign to the desired field and then subscribe to the returned observable.
myDocument.done$.subscribe(isDone => {
console.log('done: ' + isDone);
});
RxDB has multiple replication plugins to replicate database state with a server.
<Tabs>import {
replicateHTTP,
pullQueryBuilderFromRxSchema,
} from "rxdb/plugins/replication-http";
replicateHTTP({
collection: db.todos,
push: {
handler: async (rows) => {
return fetch("https://example.com/api/todos/push", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(rows),
}).then((res) => res.json());
},
},
pull: {
handler: async (lastCheckpoint) => {
return fetch(
"https://example.com/api/todos/pull?" +
new URLSearchParams({
checkpoint: JSON.stringify(lastCheckpoint)
}),
).then((res) => res.json());
},
},
});
import { replicateGraphQL } from 'rxdb/plugins/replication-graphql';
replicateGraphQL({
collection: db.todos,
url: 'https://example.com/graphql',
push: { batchSize: 50 },
pull: { batchSize: 50 }
});
The easiest way to replicate data between your clients' devices is the WebRTC replication plugin that replicates data between devices without a centralized server. This makes it easy to try out replication without having to host anything:
import {
replicateWebRTC,
getConnectionHandlerSimplePeer
} from 'rxdb/plugins/replication-webrtc';
replicateWebRTC({
collection: myDatabase.todos,
connectionHandlerCreator: getConnectionHandlerSimplePeer({}),
topic: '', // <- set any app-specific room id here.
secret: 'mysecret',
pull: {},
push: {}
})
import { replicateCouchDB } from 'rxdb/plugins/replication-couchdb';
replicateCouchDB({
collection: db.todos,
url: 'http://example.com/todos/',
push: {},
pull: {}
});
Explore all replication plugins, including advanced conflict handling and custom protocols.
<NavbarDropdownSyncList /> </Tabs> </Steps>You are now ready to dive deeper into RxDB.