Overview
Melon-db vs WatermelonDB benchmark methodology and limitations.
Melon-db ships an optional WatermelonDB baseline in the @melon-db/db-sqlite benchmark harness. This is a measurement tool only — not a performance guarantee or optimization target.
See Latest results for timings from the most recent committed benchmark run.
Commands
From the monorepo root:
bun run bench:compare # human-readable table
bun run bench:compare --scale=10k --json
bun run bench:compare --melon-engines=bun,node
bun run bench:compare --skip-wdb # Melon-db-only (no @nozbe/watermelondb leg)
bun run bench:compare:docs # refresh docs latest-results JSONCI runs bench:compare:ci (10k, JSON) in the bench-compare workflow. The job is a soft gate: it logs parity JSON and does not fail on regressions.
Fairness
| Engine | Stack | Compared to WDB? |
|---|---|---|
melon-node | createNodeSqliteAdapter + better-sqlite3 :memory: | Yes (primary axis) |
watermelon | WatermelonDB SQLiteAdapter + better-sqlite3 :memory: | Baseline |
melon-bun | createSqliteAdapter + bun:sqlite :memory: | No (informational only) |
Both sides use the same row counts and query shapes:
row-insert— onewritewith per-row createsbatch-insert— chunkedbatch/prepareCreate(≤50k scale)filtered-query— status filter, priority desc, limit 20count-query— filtered countfind-by-id— primary key lookup
Interpreting results
Parity JSON includes ratio = melonNodeMs / watermelonMs:
- < 1 — Melon-db faster on that scenario at that scale (on that machine)
- > 1 — WatermelonDB faster
Timings vary by hardware and cold JIT; treat CI output as a trend signal, not a release gate.
Requirements
- Dev dependency
@nozbe/watermelondb(bench-only) - Native better-sqlite3 bindings for
melon-nodeandwatermelonlegs
Dependencies install with Bun (better-sqlite3@12.10.0, root trustedDependencies). The entrypoint is bun run bench:compare. melon-node and watermelon legs run in a Node subprocess because better-sqlite3 is a Node native addon and does not load under Bun yet. CI sets COMPARE_RUNNER_BIN=node and provides Node 22 on the path for that subprocess only.
On-device (React Native)
Phase 28 adds a dev-only benchmark screen in apps/playground-rn-dev that reuses the same scenarios via @melon-db/db-sqlite/bench.
How to run
- Build and install the dev client (
bun run dev:rn:devorinstall:ios/install:androidfromapps/playground-rn-dev). - Start Metro (
bun run dev:rn:dev:start). - On the task list, tap Benchmarks (dev builds only) or open
/benchmark. - Choose scale 1k (quick) or 10k (full).
- Tap Run jsi-sync + Watermelon for on-device Melon-db vs WatermelonDB parity (primary), or Run jsi-sync + turbo for native binding comparison.
- Tap Share JSON report to export timings and parity (
melonVsWdband/orreport).
WatermelonDB on device requires @morrowdigital/watermelondb-expo-plugin in playground-rn-dev. Re-run install:ios / install:android (prebuild) after plugin changes before benchmarking.
Engine labels
| Engine | Stack | Notes |
|---|---|---|
melon-jsi-sync | createJsiSqliteAdapter({ mode: 'jsi-sync' }) | C++ JSI sync host object |
melon-turbo | createJsiSqliteAdapter({ mode: 'turbo' }) | Async TurboModule path |
melon-expo | createExpoSqliteAdapter | Optional leg from benchmark screen |
watermelon | WatermelonDB SQLiteAdapter + JSI (jsi: true) | Same scenarios as Node bench:compare |
On-device Melon-db vs WDB parity uses ratio = melonMs / watermelonMs (buildRnMelonVsWdbReport, default melon leg melon-jsi-sync). jsi-sync vs turbo uses buildRnParityReport. See React Native sample.
Limitations
- Manual only — no CI device farm; plug in device and disable background apps for stable numbers.
- Scales capped at 10k on device (50k/100k remain Node-only).
- WDB and Melon-db native use different SQLite stacks; jsi-sync still suspends Melon-db during its leg.
Non-goals
- Automated CI on iOS/Android simulators for device benchmarks
- Sync throughput or conflict merge benchmarks
- LokiJS in-memory WatermelonDB adapter
