@melon-db/db-sqlite
v0.1.0-alpha.0
Published
SQLite `StorageAdapter` for Bun, Node (`better-sqlite3`), Expo, and optional JSI native.
Readme
@melon-db/db-sqlite
SQLite StorageAdapter for Bun, Node (better-sqlite3), Expo, and optional JSI native.
Docs: /docs/packages/melon-db-sqlite · API
Exports
| Entry | Runtime | Expo Go |
|-------|---------|---------|
| @melon-db/db-sqlite | Bun (bun:sqlite) | — |
| @melon-db/db-sqlite/node | Node + better-sqlite3 | — |
| @melon-db/db-sqlite/expo | React Native + expo-sqlite | Yes |
| @melon-db/db-sqlite/rn | RN + @melon-db/db-sqlite-native | No (dev build only) |
| @melon-db/db-sqlite/bench | Shared benchmark scenarios (Node + RN) | — |
Expo Go (default)
import { createExpoSqliteAdapter } from '@melon-db/db-sqlite/expo';
import * as SQLite from 'expo-sqlite';
const database = await SQLite.openDatabaseAsync('app.db');
const adapter = createExpoSqliteAdapter({ database });JSI native (development build)
import { createJsiSqliteAdapter, isJsiSqliteAvailable } from '@melon-db/db-sqlite/rn';
if (isJsiSqliteAvailable()) {
const adapter = createJsiSqliteAdapter({
filename: 'app.db',
basePath: documentDirectory,
});
}Requires @melon-db/db-sqlite-native linked via expo prebuild / expo run:ios.
Scripts
bun test
bun run bench # from monorepo root — Melon-only harness
bun run bench:compare # Melon vs WatermelonDB parity (dev deps)On-device: apps/playground-rn-dev → Benchmarks (/benchmark, __DEV__ only) runs melon-jsi-sync vs melon-turbo using this package’s bench scenarios.
Reactive queries (observeQuery)
All SQLite adapters set capabilities.reactiveSubscriptions: true and implement observeQuery.
- Subscriptions dedupe by compiled query fingerprint.
- After each write, only subscriptions whose WHERE clause can be affected by the changed row are notified (predicate-aware invalidation).
- Queries with
orderBy/limit/skipinvalidate when WHERE matches (v1 may over-invalidate vs perfect top-N detection). - Per-table SQLite triggers append to
_melon_observation_events;flushObservationQueue()drains events and applies predicate-aware invalidation (including SQL that bypassesadapter.write). - Native jsi-sync registers
sqlite3_update_hook→setObservationFlushCallbackso external writes schedule a flush on the JS thread (iOS CallInvoker, Android RuntimeExecutor). Turbo path still flushes on Melon writes only. adapter.flushObservationQueue()is public for tests and manual tooling.- In-memory adapter still uses engine ChangeEmitter (collection-wide invalidation).
Comparison with WatermelonDB
bench:compare runs the same scenarios as bench for melon-node (better-sqlite3) and WatermelonDB (@nozbe/watermelondb on the Node SQLite adapter), plus optional melon-bun (bun:sqlite) for reference.
bun run bench:compare --scale=10k
bun run bench:compare --scale=10k --jsonExample parity table:
scenario melon-node watermelon ratio winner
row-insert 4200ms 5100ms 0.82 melonSee /docs/performance-comparison (methodology) and /docs/performance-comparison/latest-results (committed timings). Compare legs use [email protected] (workspace devDependency; install with root bun install and trustedDependencies). The harness starts with Bun; melon-node/watermelon run in a Node subprocess when Bun cannot load the native addon.
Author & license
Copyright (c) 2026 Nate Nichols. See LICENSE for the full MIT license text.
