Melon-dbMelon-db
Performance comparison

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 JSON

CI 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

EngineStackCompared to WDB?
melon-nodecreateNodeSqliteAdapter + better-sqlite3 :memory:Yes (primary axis)
watermelonWatermelonDB SQLiteAdapter + better-sqlite3 :memory:Baseline
melon-buncreateSqliteAdapter + bun:sqlite :memory:No (informational only)

Both sides use the same row counts and query shapes:

  • row-insert — one write with per-row creates
  • batch-insert — chunked batch / prepareCreate (≤50k scale)
  • filtered-query — status filter, priority desc, limit 20
  • count-query — filtered count
  • find-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-node and watermelon legs

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

  1. Build and install the dev client (bun run dev:rn:dev or install:ios / install:android from apps/playground-rn-dev).
  2. Start Metro (bun run dev:rn:dev:start).
  3. On the task list, tap Benchmarks (dev builds only) or open /benchmark.
  4. Choose scale 1k (quick) or 10k (full).
  5. Tap Run jsi-sync + Watermelon for on-device Melon-db vs WatermelonDB parity (primary), or Run jsi-sync + turbo for native binding comparison.
  6. Tap Share JSON report to export timings and parity (melonVsWdb and/or report).

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

EngineStackNotes
melon-jsi-synccreateJsiSqliteAdapter({ mode: 'jsi-sync' })C++ JSI sync host object
melon-turbocreateJsiSqliteAdapter({ mode: 'turbo' })Async TurboModule path
melon-expocreateExpoSqliteAdapterOptional leg from benchmark screen
watermelonWatermelonDB 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