Embedded and remote SurrealDB for React Native, powered by the official SurrealDB Rust SDK through generated UniFFI/Hermes JSI bindings.
Warning
This project is an early alpha. Pin exact versions, read the known limitations, and test your own persistence and upgrade paths before shipping it.
SurrealDB's official Expo guide documents that its JavaScript embedded engines cannot run on React Native: Hermes does not provide the WebAssembly runtime they need, and the Node.js engine is a native Node addon. Expo and React Native apps therefore normally connect to a remote SurrealDB instance.
This project fills that mobile embedding gap differently. It packages the official Rust SDK as a native React Native module, so SurrealDB runs inside the iOS or Android app process. The same API can also connect to a remote SurrealDB server over WebSocket.
I see it as another option in the space normally occupied by SQLite on mobile: an embedded, local database for React Native apps, but with SurrealQL plus document, graph, relational, and live-query capabilities. It is an architectural alternative, not a drop-in replacement—the query language, data model, runtime, binary footprint, and maturity are different, and each app should benchmark its own workload.
- Embedded in-memory databases and experimental persistent SurrealKV databases
- Remote
ws://andwss://connections - SurrealQL queries, variables, namespace/database selection, authentication, invalidation, and close
- Callback and manually managed native transaction handles with commit, cancellation, and automatic rollback when a callback throws
- Cancellable live queries as pull-based async iterators
- Multicast live-query subscriptions and an optional TanStack Query-style React hook
- Lossless transport for 64-bit integers, decimals, bytes, UUIDs, record IDs,
NONE, sets, and other SurrealDB-specific values - React Native's New Architecture and Hermes on iOS and Android
- Prebuilt native artifacts for supported release architectures
- Device-side correctness, persistence, lifecycle, size, and performance testing
- Paired SurrealDB/OP-SQLite workloads adapted from
sqlite-bench
The current package targets React Native 0.82 or newer, iOS 15.1 or newer, and Android API 24 or newer. It contains custom native code, so it requires a native development build and does not run in Expo Go.
Install the current npm alpha with:
pnpm add react-native-surrealdb
cd ios && pod installimport { SurrealRecordId, connect } from "react-native-surrealdb";
const db = await connect({
endpoint: "memory",
namespace: "app",
database: "app",
});
const [result] = await db.query("RETURN $person", {
person: new SurrealRecordId("person:ada"),
});
await db.close();See the package README for live queries, the React hook, supported platforms, native development, and the release process.
Maintainers create an immutable GitHub prerelease tarball for production-app testing before making a separate, approval-gated npm publication. See the release guide for versioning, candidate tags, trusted publishing, provenance, and stable promotion.
- SurrealKV support remains experimental.
- iOS simulator builds require Apple Silicon. Intel Mac simulators cannot load this alpha because its x86_64 iOS slice was removed to keep the npm package below the registry's effective upload-size boundary. Android x86_64 emulators remain supported.
- Automatic WebSocket reconnection, live-query re-subscription, and duplicate suppression across reconnects are not implemented yet.
- This is a database binding, not yet a local-first synchronization engine. An embedded database and a remote database do not automatically replicate.
- The compatibility and durability matrix is still growing; this is not a stable API promise yet.
The longer-term goal is to explore an optional sync layer on top of the native database binding. That work would remain separate from the core package and would need to provide a real replication protocol: durable mutation IDs and an outbox, server checkpoints, initial snapshots and incremental catch-up, idempotency, conflict and tombstone semantics, schema negotiation, retry and authentication recovery, and crash-safe resume.
Syncular is the closest current reference: it already offers an offline-first SQL sync design and a React Native integration. The first step is to evaluate whether an adapter or collaboration makes more sense than building another engine.
Electric's durable transport work is also useful research for resumable, addressable streams. Its current packages target AI SDK transports and durable collaborative sessions, however, so it is an architectural reference rather than a drop-in database sync engine for this project.
No sync capability will be advertised until it has explicit authorization, conflict, offline recovery, migration, and adversarial failure tests.
This is not a one-off experiment. I use the package in a production app every day and intend to maintain it for the long term. The app's public App Store launch is still awaiting approval, but the package is already exercised by a real product rather than only by the example harness.
The implementation and research were informed by the
SurrealDB Rust SDK,
uniffi-bindgen-react-native,
Mozilla UniFFI,
Jazz's React Native Rust crate,
Turso's React Native binding,
and React Native Harness.
Thank you to the people maintaining those projects and publishing their work.
In particular, uniffi-bindgen-react-native is led by James Hugman, builds on
Mozilla's original UniFFI bindings-generator ecosystem, and credits Filament,
Mozilla, and LiveKit for collaboration or funding. Without that foundation this
project's native bridge would not exist.
The test and benchmark work deserves its own explicit credit:
- OP-SQLite informed the mobile benchmark workload categories, Release-app execution pattern, cooldowns, and the need to measure both query completion and full JSI value materialization.
- Oscar Franco's
sqlite-benchwas the source for the paired SQLite/SurrealDB benchmark adaptation. The repository history pins the studied revision and records what was adapted or excluded. - SurrealDB's
crud-benchis the source for the workload matrix adapted by the current mobile benchmark suite, with pinned source links beside the translated cases. - React Native Harness and React Native Test App provide the real React Native runtime, device orchestration, and maintainable native hosts used for integration and benchmark runs.
The adapted code and the upstream projects remain under their respective licenses. See THIRD_PARTY_NOTICES.md for consolidated project and license attribution, and PERFORMANCE.md for methodology, provenance, limitations, and pinned workload references.
The project was built entirely with AI under my direction, review, and device validation, mostly using Codex with GPT-5.6 Sol at medium reasoning effort. This disclosure is about how the code was produced, not a claim that generated code is automatically correct; the native test matrix and release checks remain the standard for accepting changes.
This repository is a pnpm workspace containing the Rust core, the published React Native package, and five static compatibility apps:
| Path | Purpose |
|---|---|
crates/surrealdb-rn-core |
Rust API exposed through UniFFI |
packages/react-native-surrealdb |
Published TypeScript, JSI/C++, iOS, and Android package |
apps/harness-shared |
Application, integration tests, and benchmarks shared by every test app |
apps/harness-rn82 … apps/harness-rn86 |
One React Native Test App host per supported React Native version |
The React Native versions are pinned as named catalogs in
pnpm-workspace.yaml. No maintenance script rewrites a
host's package.json.
Commands run through pnpm run use executables from the relevant workspace
package's node_modules/.bin; they are not expected to be installed globally.
| Command | Provided by | What it does here |
|---|---|---|
ubrn |
uniffi-bindgen-react-native, a dependency of react-native-surrealdb |
Builds the Rust libraries and generates the UniFFI TypeScript/C++/TurboModule bindings |
bob |
react-native-builder-bob, a dev dependency of react-native-surrealdb |
Builds the publishable ESM JavaScript and TypeScript declarations into lib/ |
configure-test-app |
react-native-test-app, a dependency of each harness |
Regenerates an RNTA native host from its app.json manifest |
rock |
rock, a dependency of each harness |
Starts Metro or builds/runs a native app, using the configured GitHub remote build cache |
react-native-harness |
react-native-harness, a dependency of each harness |
Installs/runs the app and executes device-side integration or benchmark tests |
react-native |
React Native and its community CLI packages in each harness | Bundles JavaScript or builds/runs a host without Rock |
vitest, tsc, eslint, prettier |
Package-local development dependencies | Run unit tests and static checks |
cargo, rustup |
The Rust toolchain pinned by rust-toolchain.toml |
Build, test, lint, format, and install target standard libraries for the Rust core |
bundle, pod |
Ruby Bundler and CocoaPods | Resolve the iOS host's native dependencies |
surreal |
The optional SurrealDB CLI | Starts a real server for the ignored WebSocket integration test |
For example, this selects the package workspace and then runs its ubrn:ios
script. The ubrn inside that script resolves from
packages/react-native-surrealdb/node_modules/.bin:
pnpm --filter react-native-surrealdb run ubrn:iosIf a local executable cannot be found, install the pinned workspace dependencies instead of installing the command globally:
pnpm install --frozen-lockfileThe repository requires Node.js 20 or newer and pnpm 11 or newer; CI currently
uses Node.js 22 and pnpm 11.5.0. Platform builds additionally require Xcode and
CocoaPods on macOS, or an Android SDK, NDK 27, Java, and cargo-ndk for
Android. The complete Rust target list is recorded in
packages/react-native-surrealdb/RELEASING.md.
Run the narrow checks while developing:
pnpm install
./scripts/verify-core.sh
pnpm --filter react-native-surrealdb test
pnpm --filter react-native-surrealdb typecheckThe root package.json provides these repository-wide commands:
| Command | What it runs |
|---|---|
pnpm build |
Runs every workspace's build script. Currently this is the package's Bob build; the harness bundle scripts are named build:android and build:ios and are therefore not included. |
pnpm format |
Checks the package's TypeScript/JSON/YAML with Prettier, then checks all Rust code with cargo fmt. It reports differences but does not rewrite normal source files. |
pnpm lint |
Runs the package TypeScript check and ESLint for all five compatibility hosts. |
pnpm test |
Runs workspace scripts named exactly test. Currently this is the package Vitest suite; Harness tests and benchmark-tool tests have explicit names and are not included. |
pnpm typecheck:react-native-matrix |
Type-checks RN 0.82 through 0.86 sequentially so failures identify a particular host. |
./scripts/verify-core.sh |
Runs Rust formatting, Clippy with warnings denied, Rust unit tests, and cross-compiles the core for iOS Simulator and Android arm64. |
verify-core.sh expects the corresponding Rust targets to be installed. Its
Android check uses ANDROID_NDK_HOME when set, otherwise it looks below
~/Library/Android/sdk/ndk.
The ubrn:* scripts live in
packages/react-native-surrealdb/package.json:
| Command | Result |
|---|---|
pnpm --filter react-native-surrealdb run ubrn:ios |
Builds release libraries for arm64 iOS devices and Apple Silicon simulators, creates SurrealDbRnFramework.xcframework, and regenerates the UniFFI bindings. The deployment target is iOS 15.1. |
pnpm --filter react-native-surrealdb run ubrn:android |
Builds release .so files for arm64-v8a and x86_64 under android/src/main/jniLibs, and regenerates the bindings. |
pnpm --filter react-native-surrealdb run ubrn:android:size |
Builds only arm64 Android, which is sufficient for the controlled release-size benchmark. Do not use this reduced artifact set for publishing. |
pnpm --filter react-native-surrealdb run release:artifacts |
Runs the full iOS and Android ubrn builds, then strips non-runtime symbols from the distributable native libraries. |
pnpm --filter react-native-surrealdb run format:generated |
Rewrites the generated TurboModule entry files with Prettier. The ubrn:* scripts run it automatically. |
--and-generate in these scripts means “build Rust and regenerate bindings”;
--release selects optimized Rust artifacts; --targets lists the Rust target
triples to include. Their paths and output names are configured in
ubrn.config.yaml.
The XCFramework and Android jniLibs outputs are intentionally ignored because
they are large and platform-generated. The binding source in src/generated/,
cpp/generated/, src/native.tsx, and src/NativeSurrealdb.ts is checked in.
After changing the UniFFI surface, regenerate all artifacts, review the
generated source diff, and commit that source diff.
All commands below target the published package:
| Command | What it means |
|---|---|
pnpm --filter react-native-surrealdb run build |
Runs Bob and recreates publishable ESM and declaration output in lib/. |
... run test |
Runs the Vitest host/unit suite once. |
... run typecheck |
Runs tsc --noEmit. |
... run lint |
Also runs tsc --noEmit; this alias lets the root recursive lint command include the package. |
... run format |
Checks package source, tests, and top-level JSON/YAML with Prettier. |
... run verify:package |
Checks built output, generated bindings, the retained iOS/Android architectures, and package metadata. |
... run release:pack -- /path/to/output |
Packs the release without rerunning generators and rejects tarballs larger than 180,000,000 bytes. |
... run release:check |
Runs build, type-check, tests, and package verification. It does not create missing native artifacts. |
pnpm --filter react-native-surrealdb pack |
Runs prepack (therefore release:check) and creates the npm tarball for consumer testing. |
pnpm --filter react-native-surrealdb publish … |
Runs prepublishOnly (also release:check) before publishing. Follow the release guide rather than invoking this casually. |
The workspace root is private and must never be published. Publish only the
tested tarball produced for packages/react-native-surrealdb. Pull-request CI
assembles that complete package from stripped iOS and Android artifacts, checks
its exact npm name, and rejects it if the compressed tarball exceeds
180,000,000 bytes.
Prepare native artifacts before a release check:
pnpm --filter react-native-surrealdb run release:artifacts
pnpm --filter react-native-surrealdb run release:check
pnpm --filter react-native-surrealdb packSee packages/react-native-surrealdb/RELEASING.md
for target installation, package-size review, and the manual publish step.
Each static RNTA host imports the same code from apps/harness-shared:
| Workspace filter | React Native |
|---|---|
surrealdb-harness-rn82 |
0.82.1 |
surrealdb-harness-rn83 |
0.83.10 |
surrealdb-harness-rn84 |
0.84.1 |
surrealdb-harness-rn85 |
0.85.3 |
surrealdb-harness-rn86 |
0.86.0 |
Replace the filter in these examples to test another supported version:
| Command | Purpose |
|---|---|
pnpm --filter surrealdb-harness-rn86 run start |
Starts Metro through Rock. |
... run rock:android |
Builds or restores the Android app through Rock, then runs it. |
... run rock:ios |
Prepares iOS artifacts and Pods, then builds or restores and runs through Rock. |
... run android |
Uses the React Native CLI directly instead of Rock. |
... run ios |
Prepares iOS, then uses the React Native CLI directly. Set SURREALDB_IOS_SIMULATOR to override the default simulator. |
... run prepare:ios |
Creates the missing XCFramework and JS bundle, and runs bundle exec pod install when the Pods project does not link the framework. |
... run build:android / ... run build:ios |
Produces a development JS bundle and assets in dist/; these do not compile a native app. |
... run test:harness:android / ... run test:harness:ios |
Runs device integration tests with React Native Harness. A compatible emulator/simulator or HARNESS_APP_PATH must be available. |
... run lint |
Lints shared app/test code using that React Native version's ESLint configuration. |
... run typecheck |
Type-checks shared code against that host's React Native and React versions. |
... run configure |
Runs RNTA's configure-test-app generator. Use only after intentionally changing app.json or RNTA/native configuration. |
configure is not a routine prerequisite. It can rewrite android/, ios/,
and package metadata based on RNTA defaults. Always run it in only the intended
host and review git diff before keeping its changes. Application and tests
belong in apps/harness-shared; host-specific native configuration belongs in
the host's app.json.
For example:
pnpm --filter surrealdb-harness-rn82 run rock:android
pnpm --filter surrealdb-harness-rn84 run test:harness:android
pnpm typecheck:react-native-matrixRock fingerprints each host's native files, resolved dependencies, React Native
version, and the shared Rust/package sources. Locally, its GitHub provider reads
GITHUB_TOKEN or the authenticated GitHub CLI session. A cache miss performs a
native build and uploads the result; a matching later invocation restores it.
CI builds the Rust native artifact once per platform before running the
five-version Rock matrix. Details live in
apps/harness-rn86/README.md and
.github/workflows/react-native-compatibility.yml.
RN 0.86 is the reference host for size and device performance measurements. These scripts are intentionally not duplicated in older hosts:
| Command | Purpose |
|---|---|
pnpm --filter surrealdb-harness-rn86 run size:android |
Builds an arm64 release candidate and compares it with the committed reference or BASELINE_APK. |
... run size:android:baseline |
Builds and records a stock RNTA app without this package. |
... run size:android:benchmark |
Builds a fresh stock baseline and the candidate, then performs the paired comparison. Run ubrn:android:size first. |
... run benchmark:android / ... run benchmark:ios |
Runs the short smoke device benchmark. |
... run benchmark:android:canonical / ... run benchmark:ios:canonical |
Runs the 2,000-record regression profile. |
... run benchmark:android:upstream / ... run benchmark:ios:upstream |
Runs the 10,000-record upstream-shaped profile. |
... run test:benchmark-tools |
Tests the Node report extraction and comparison utilities without a device. |
Size reports are written below apps/harness-rn86/size-results/; benchmark
reports and captured device logs go below
apps/harness-rn86/performance-results/. Both output directories are ignored.
Set SURREALDB_PERFORMANCE_BASELINE to an absolute report path to enable the
performance regression gate. See PERFORMANCE.md and the
harness README for the measurement rules and baseline compatibility checks.
For a TypeScript facade change:
pnpm --filter react-native-surrealdb run test
pnpm --filter react-native-surrealdb run typecheck
pnpm --filter react-native-surrealdb run build
pnpm typecheck:react-native-matrixFor a Rust or UniFFI API change:
./scripts/verify-core.sh
pnpm --filter react-native-surrealdb run release:artifacts
pnpm --filter react-native-surrealdb run release:check
pnpm typecheck:react-native-matrixThen inspect the generated binding changes and exercise at least one iOS and one Android compatibility host. The five-version native matrix itself runs in GitHub Actions.
When adding or upgrading a supported React Native version, update its named
catalog in pnpm-workspace.yaml, create or update a dedicated static host,
review any deliberate RNTA regeneration, update the compatibility workflow
matrix, reinstall with the frozen lockfile, and run the TypeScript matrix.
Keeping independent manifests and native directories prevents one version's
generator output or native cache from leaking into another.
To exercise the opt-in authenticated WebSocket integration test, start a local server and run:
surreal start --no-banner --bind 127.0.0.1:18080 --user root --pass root memory
SURREAL_TEST_WS_ENDPOINT=ws://127.0.0.1:18080 \
cargo test -p surrealdb-rn-core authenticated_websocket_live_query -- --ignoredThe Rust toolchain and dependency graph are pinned through
rust-toolchain.toml and Cargo.lock.
- Architecture research
- Performance and device-test strategy
- Native size and Rust implementation decisions
The original code in this repository is available under the MIT License. Bundled dependencies and generated artifacts remain subject to their respective licenses and are documented in third-party notices. SurrealDB is a trademark of SurrealDB Ltd.; this independent project is not affiliated with or endorsed by SurrealDB Ltd.