Benchmarks

There are no published numbers on this page. Pick the engines, the suites, and the dataset size, and all three databases are built and measured here, in your browser, on your machine — which is the only place a browser database’s performance means anything. The initial selection compares Minnow on IndexedDB and OPFS with SQLite using primary keys only at 5× scale; 1×, 2×, 5×, and 10× are available, while cached repeats, secondary indexes, and PGlite are opt-in.

Reads and writes stay split by OLTP and OLAP throughout, because a blended score hides the trade-off: selective lookups, scans, bulk loads, and small writes can favor different engines. Performance depends on the workload and browser. Every result is checked against an independent oracle before its timing counts, and an engine that got the wrong answer reports no number at all.

Engines
Suites
Dataset

478k rows across 50 tables, about 47.3 MB of browser storage for the engines selected.

How it works

The dataset is a deterministic 50-table commerce schema generated from a closed-form function of the row index, which is what makes the oracles possible: every expected answer is recomputed in JavaScript from the same inputs the engines were given, rather than read back out of one of them.

The harness uses matching declared indexes and leaves query-planner and memory settings at their shipped defaults. SQLite runs PRAGMA optimize after loading. Minnow uses gzip blocks and relaxed durability; PGlite uses relaxed reads and strict writes, while SQLite keeps its default durability. These storage costs differ, so the timings are not isolated executor costs. Each database persists to the storage its own documentation recommends, named per engine above and reported exactly as the engine installed it once a run has finished. The workload declares the same primary keys and foreign-key secondary indexes for all engines. Bulk inserts and post-load index builds are reported separately, so an index cannot make a read faster by hiding its build cost in the load number. Choose primary keys only to measure the same workload without those secondary indexes. The storage table separates table data from index bytes. Only the engine’s own call is timed; reshaping rows into the form each API wants is the harness’s cost and is excluded.

All comparison engines already run in the benchmark’s dedicated web worker. The read table therefore compares their engine calls directly instead of adding a second, nested worker channel to Minnow alone. The live-query suite still usesMinnowDatabaseClient, because notification delivery across that channel is the behavior it measures.

Timings are taken by the batch. Clock resolution varies by browser and origin isolation, so fast reads are repeated inside a timed window and divided by the execution count. Each cell reports the median of those windows after an untimed warm-up. Cached repeats are labeled separately. The live suite measures only Minnow’s implemented subscription drivers; PGlite’s live-query extension is not measured here.

Running a suite writes real data to your browser’s storage for this origin. Use one tab at a time — PGlite allows only one open instance per data directory.