TanStack DB with SQLite: Native & WASM Storage via RxDB
TanStack DB is an in-memory reactive client store with live queries and optimistic mutations, and it delegates persistence and sync to the collection type you choose. The official @tanstack/rxdb-db-collection package puts RxDB underneath, as described in the TanStack DB + RxDB overview. With the SQLite RxStorage, that RxDB layer writes your TanStack DB SQLite data into a real SQLite database: native on Node.js, Electron, React Native, and Capacitor, or compiled to WebAssembly in the browser. This page explains the two versions of the SQLite storage, lists the sqliteBasics adapters for the common SQLite bundles, walks through a runnable Node.js example, and compares the setup with TanStack DB's own SQLite persistence packages.
Why SQLite Under TanStack DBโ
SQLite is already there on most platforms where your app runs. Android and iOS ship with a built-in SQLite engine, Node.js version 22 and newer contains the node:sqlite module, and Electron apps can bundle SQLite with the main process. On mobile devices, SQLite stores data on the filesystem instead of inside browser-managed storage, so it is not subject to the cleanup rules that apply to IndexedDB. SQLite has been battle-tested for decades. It is a solid place for your local data.
TanStack DB keeps its collections in memory. When you combine it with the RxDB collection, every optimistic mutation is persisted through RxDB into SQLite, and on the next app start the TanStack DB collection loads its initial state back from the SQLite file. Changes that reach RxDB from replication or from direct RxDB code stream into the TanStack DB collection automatically. The how it works section of the hub article describes the two loops in detail.
Trial Version and Premium Versionโ
The SQLite storage exists in two versions:
- Trial version: Shipped for free with the RxDB core package. Import
getRxStorageSQLiteTrialfromrxdb/plugins/storage-sqlite. It passes the full RxDB storage test suite, but it is limited to500non-deleted documents, does not use indexes, has no attachment support, and fetches the whole storage state to run queries in memory. Use it for evaluation and prototypes only. - RxDB Premium ๐ version: The production-ready storage. Import
getRxStorageSQLitefromrxdb-premium/plugins/storage-sqlite. It has full query support with indexes and a load of performance optimizations.
Both versions share the same API. Moving from the trial to the premium storage is an import change, not a rewrite, so you can build your whole TanStack DB integration on the trial version first.
The sqliteBasics Adaptersโ
Different SQLite libraries have different APIs to open a database and run statements. Some use callbacks, some use Promises. The RxDB SQLite storage abstracts this behind a SQLiteBasics interface, and RxDB ships ready-made implementations for the common SQLite bundles:
getSQLiteBasicsNodeNative()for thenode:sqlitemodule built into Node.js 22 and newer.getSQLiteBasicsNode()for thesqlite3npm package.getSQLiteBasicsWasm()for wa-sqlite, SQLite compiled to WebAssembly for the browser.getSQLiteBasicsQuickSQLite()forreact-native-quick-sqlitein bare React Native projects.getSQLiteBasicsExpoSQLiteAsync()forexpo-sqlitein current Expo SDK versions, andgetSQLiteBasicsExpoSQLite()for the non-async API of older Expo SDKs.getSQLiteBasicsWebSQL()forreact-native-sqlite-2.getSQLiteBasicsCapacitor()for@capacitor-community/sqlitein Capacitor apps.getSQLiteBasicsTauri()for the Tauri SQL plugin.
Notice that the storage requires SQLite version 3.38.0 or newer because it uses the SQLite JSON functions like JSON_EXTRACT to query document fields. The full code samples for every adapter are on the SQLite RxStorage page.
Example: TanStack DB on SQLite in Node.jsโ
The following example runs on plain Node.js 22 or newer with the free trial storage and the built-in node:sqlite module. No native compilation step is needed.
Install the Packagesโ
npm install rxdb rxjs @tanstack/react-db @tanstack/rxdb-db-collectionThe @tanstack/react-db package exports the framework-independent createCollection(), so this also works outside of React and with the Vue, Solid, Svelte, and Angular bindings.
Create the RxDatabase on the SQLite Storageโ
import { createRxDatabase } from 'rxdb/plugins/core';
import {
getRxStorageSQLiteTrial,
getSQLiteBasicsNodeNative
} from 'rxdb/plugins/storage-sqlite';
import { DatabaseSync } from 'node:sqlite';
const db = await createRxDatabase({
name: 'exampledb',
storage: getRxStorageSQLiteTrial({
sqliteBasics: getSQLiteBasicsNodeNative(DatabaseSync)
})
});
await db.addCollections({
todos: {
schema: {
title: 'todos',
version: 0,
type: 'object',
primaryKey: 'id',
properties: {
id: { type: 'string', maxLength: 100 },
text: { type: 'string' },
completed: { type: 'boolean' }
},
required: ['id', 'text', 'completed']
}
}
});Wrap the RxCollection in a TanStack DB Collectionโ
import { createCollection } from '@tanstack/react-db';
import { rxdbCollectionOptions } from '@tanstack/rxdb-db-collection';
const todosCollection = createCollection(
rxdbCollectionOptions({
rxCollection: db.todos
})
);Mutate and Observe the Durable Dataโ
// Observe the RxDB collection to see writes arrive in SQLite.
db.todos.find().$.subscribe((docs) => {
// The count grows on every run of this script
// because the data survives the process restart.
console.log('todos in SQLite:', docs.length);
});
// Optimistic mutation on the TanStack DB collection,
// persisted through RxDB into the SQLite file.
todosCollection.insert({
id: 'todo-' + Date.now(),
text: 'stored in SQLite',
completed: false
});Run the script twice. The second run starts with the todos from the first run because they live in the SQLite database, not in memory. In a UI app you would read the data with useLiveQuery as shown in the hub article.
To go to production, swap the storage import for the premium version:
import {
getRxStorageSQLite,
getSQLiteBasicsNodeNative
} from 'rxdb-premium/plugins/storage-sqlite';
import { DatabaseSync } from 'node:sqlite';
const storage = getRxStorageSQLite({
sqliteBasics: getSQLiteBasicsNodeNative(DatabaseSync)
});Everything else stays the same.
SQLite via WASM in the Browserโ
In the browser there is no native SQLite, but the wa-sqlite package runs SQLite as WebAssembly and can persist to IndexedDB or OPFS underneath:
import {
createRxDatabase
} from 'rxdb';
import {
getRxStorageSQLite,
getSQLiteBasicsWasm
} from 'rxdb-premium/plugins/storage-sqlite';
import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite-async.mjs';
import SQLite from 'wa-sqlite';
const sqliteModule = await SQLiteESMFactory();
const sqlite3 = SQLite.Factory(sqliteModule);
const myRxDatabase = await createRxDatabase({
name: 'exampledb',
storage: getRxStorageSQLite({
sqliteBasics: getSQLiteBasicsWasm(sqlite3)
})
});Keep in mind that SQLite via WebAssembly is slower than the IndexedDB or OPFS storages because sending data between the main thread and WASM adds latency, see the performance comparison. When you do not have a hard requirement on SQLite in the browser, follow the IndexedDB and OPFS guide instead. Your TanStack DB code does not change either way.
Mobile and Desktop Platformsโ
On mobile and desktop, native SQLite is the recommended storage for RxDB and by extension for TanStack DB:
- React Native and Expo: Use
getSQLiteBasicsQuickSQLite()withreact-native-quick-sqlitein bare projects, orexpo-sqlitein Expo apps. Details are in the React Native database guide and the TanStack DB React Native article. - Electron: Run the storage in the main process so database work does not block rendering. See the Electron database guide and the TanStack DB Electron article.
- Capacitor: Use
getSQLiteBasicsCapacitor()with@capacitor-community/sqlite. See the Capacitor database guide and the TanStack DB Capacitor article.
For TanStack DB with Expo SQLite, the setup looks like this:
import {
createRxDatabase
} from 'rxdb';
import {
getRxStorageSQLite,
getSQLiteBasicsExpoSQLiteAsync
} from 'rxdb-premium/plugins/storage-sqlite';
import * as SQLite from 'expo-sqlite';
const myRxDatabase = await createRxDatabase({
name: 'exampledb',
multiInstance: false,
storage: getRxStorageSQLite({
sqliteBasics: getSQLiteBasicsExpoSQLiteAsync(SQLite.openDatabaseAsync)
})
});Then wrap the collections with rxdbCollectionOptions() exactly as in the Node.js example above. Notice that for Expo apps the Expo Filesystem RxStorage exists as a faster alternative to SQLite.
TanStack DB's Own SQLite Persistenceโ
TanStack DB ships its own SQLite persistence layer: the @tanstack/db-sqlite-persistence-core package with platform adapters for the browser (wa-sqlite), Node.js, Electron, Expo, React Native, and Capacitor. When your only goal is to make a local-only TanStack DB collection survive a restart on one platform, those packages do the job and you do not need RxDB.
The RxDB SQLite storage covers a different scope. It puts a full database under your store, and the SQLite file becomes one part of a larger system:
- Replication with any backend through the Sync Engine, including GraphQL, CouchDB, Supabase, and custom HTTP endpoints, with conflict resolution and offline resume.
- Encryption of the data stored inside SQLite.
- Schema migrations for when your data model changes between app versions.
- Multi-tab support with leader election when the app runs in multiple browser tabs.
- Storage portability: The same code runs on IndexedDB, OPFS, localStorage, or the Node.js filesystem storage. Switching storages is a configuration change, not a rewrite.
FAQโ
Is there a free SQLite storage for TanStack DB with RxDB?
Yes. The trial version of the SQLite RxStorage ships with the free RxDB core package as getRxStorageSQLiteTrial. It is limited to 500 non-deleted documents and is meant for evaluation and prototypes. The production version with indexes and full query support is part of RxDB Premium ๐.
Can TanStack DB use SQLite WASM in the browser?
Yes. The premium SQLite storage supports wa-sqlite through the getSQLiteBasicsWasm() adapter, so your TanStack DB collections persist into WebAssembly SQLite. In most browser apps the IndexedDB storage or OPFS storage is the faster choice, and your TanStack DB code stays identical when you switch.
Does TanStack DB work with Expo SQLite?
Yes. The getSQLiteBasicsExpoSQLiteAsync() adapter connects the SQLite storage to the expo-sqlite module, and the TanStack DB collection sits on top through rxdbCollectionOptions(). The React Native database guide lists the recommended adapters per environment, including the faster Expo Filesystem storage.
Do I have to change my TanStack DB code when I switch from SQLite to another storage?
No. The storage is set once when the database is created, and the RxStorage interface hides it from everything above. Your TanStack DB collections, live queries, and mutations keep working unchanged on IndexedDB, OPFS, SQLite, or any other storage.
Follow Upโ
- Read the TanStack DB + RxDB overview for the full integration guide.
- See all adapters and options on the SQLite RxStorage page.
- Persist in the browser without SQLite: IndexedDB and OPFS for TanStack DB.
- Platform guides: React Native, Electron, and Capacitor.
- Start with the RxDB Quickstart.
- Check out the RxDB GitHub repository and leave a star โญ.
- Join the RxDB Discord to discuss your setup.