@melon-db/db-sqlite-native
v0.1.0-alpha.0
Published
Melon JSI/TurboModule SQLite for React Native development builds
Readme
@melon-db/db-sqlite-native
Melon-owned SQLite native module for React Native development builds.
Not available in Expo Go. Use @melon-db/db-sqlite/expo for Expo Go and managed workflows.
Docs: Native SQLite architecture · Package guide
Platform support
| Platform | Native binding | Status |
|----------|----------------|--------|
| iOS (dev build) | Sync C++ JSI (global.melonSqliteJsi) + TurboModule fallback | Supported |
| Android (dev build) | Sync C++ JSI (global.melonSqliteJsi) + TurboModule fallback | Supported |
| Expo Go | N/A | Not available |
RN SQLite paths
| Path | Export | Binding |
|------|--------|---------|
| Expo Go (default) | @melon-db/db-sqlite/expo | expo-sqlite async |
| Dev build (fast) | @melon-db/db-sqlite/rn + mode: 'auto' | Sync C++ JSI + dedicated DB queue |
| Dev build (legacy) | @melon-db/db-sqlite/rn + mode: 'turbo' | Async TurboModule promises |
Limitations
- Kotlin TurboModule
exec()routesPRAGMAthroughrawQueryon the async fallback path only (C++ JSI usessqlite3_exec). - BLOB /
bytesfields are not round-tripped on the native path (returned asnull). - Predicate-aware
observeQueryships in@melon-db/db-sqlite(shared adapter-core); native path uses the same invalidation. - Sync JSI calls block the JS thread until the native DB queue completes (intentional for throughput; keep queries bounded).
Requirements
- React Native 0.76+ with New Architecture enabled
expo prebuildor bare React Native with autolinking
Codegen (TurboModule)
Spec: src/NativeMelonSQLite.ts. Regenerate artifacts after spec changes:
cd apps/playground-rn-dev
# iOS
node node_modules/react-native/scripts/generate-codegen-artifacts.js \
-p ../../packages/melon-db-sqlite-native \
-t ios \
-o ../../packages/melon-db-sqlite-native/ios/generated \
-s library
# Android (updates android/src/main/java/com/facebook/fbreact/specs/NativeMelonSQLiteSpec.java)
node node_modules/react-native/scripts/generate-codegen-artifacts.js \
-p ../../packages/melon-db-sqlite-native \
-t android \
-o ../../packages/melon-db-sqlite-native/android/build \
-s libraryThen run expo prebuild --clean in apps/playground-rn-dev before native builds.
Gradle also generates android/build/generated/source/codegen/java when newArchEnabled=true during app builds.
Usage
Apps should not import this package directly. Use @melon-db/db-sqlite/rn:
import { Paths } from 'expo-file-system';
import { createJsiSqliteAdapter, isJsiSqliteAvailable } from '@melon-db/db-sqlite/rn';
if (!isJsiSqliteAvailable()) {
throw new Error('Use a development build or switch to @melon-db/db-sqlite/expo');
}
const adapter = createJsiSqliteAdapter({
filename: 'app.db',
basePath: Paths.document.uri.replace(/^file:\/\//, ''),
mode: 'auto', // prefers sync JSI when installed (iOS + Android)
});Inspect binding mode:
import { getMelonSQLiteNativeMode } from '@melon-db/db-sqlite-native';
// 'jsi-sync' when C++ host object installed
// 'turbo' when forcing async path or host object absent
// null in Expo GoForce async TurboModule for A/B comparison:
EXPO_PUBLIC_MELON_SQLITE=turbo bun run dev:rn:dev:startDevelopment build (playground-rn-dev)
# iOS
bun run dev:rn:dev
bun run dev:rn:dev:start
# Android
bun run dev:rn:dev:android
bun run dev:rn:dev:startExpo Go demo: apps/playground-rn (bun run dev:rn).
Optional: EXPO_PUBLIC_MELON_SQLITE=expo in the dev app uses expo-sqlite instead of native.
Manual verification checklist
iOS
After bun run dev:rn:dev (or install:ios in apps/playground-rn-dev):
- App launches without native module errors.
- Runtime badge shows
native jsi-sync (ios)(ornative turbo (ios)whenEXPO_PUBLIC_MELON_SQLITE=turbo). - Seeded tasks appear (same as expo path).
- Add / complete tasks persist across restart.
- Sync demo works against
bun run sync-server. - Benchmarks: open Benchmarks from the task screen (
__DEV__) or navigate to/benchmark; run jsi-sync + turbo @ 10k and share the JSON report.
Android
After expo prebuild --clean + bun run dev:rn:dev:android then bun run dev:rn:dev:start:
- App launches without native module errors.
- Runtime badge shows
native jsi-sync (android)(ornative turbo (android)whenEXPO_PUBLIC_MELON_SQLITE=turbo). - Seeded tasks appear.
- Add / complete tasks persist across restart.
- Sync demo works against
bun run sync-server.
Architecture
- Shared C++:
cpp/MelonSQLiteHostObject.cpp+MelonSQLiteInstaller.cpp— sync JSI host object (openSync,queryAllSync, …) with a dedicated serial DB queue (GCD on iOS, worker thread on Android). - iOS install:
MelonSQLiteTurboModule.mmcallsinstallMelonSqliteJsion first Turbo dispatch. - Android install:
MelonSQLiteJni+ NDKlibmelon_sqlite.soinstalls viaRuntimeExecutoron first Turbo call fromMelonSQLiteModule. - Fallback:
MelonSQLiteTurboModule (MelonSQLiteSpeccodegen) with async promises on both platforms. - JS:
MelonSQLiteJsi.tsreadsglobal.melonSqliteJsi;MelonSQLiteBridge.tsreportsjsi-sync|turbo|bridge.
Observation (Phase 29): sqlite3_update_hook on JSI openSync schedules setObservationFlushCallback on the JS thread (coalesced). Pair with @melon-db/db-sqlite flushObservationQueue to process _melon_observation_events. Turbo/async native path does not install the hook in v1.
Author & license
Copyright (c) 2026 Nate Nichols. See LICENSE for the full MIT license text.
