Benchmarks / methodology
Benchmark methodology
The benchmarks separate workload time from setup and reopening. This page explains the SQL, correctness checks, and timing boundaries so you can interpret the results.
What we time
Each backend runs sequentially with deterministic input. The runner separates preparation, initialization, measured work, persistence barriers, and reopen mount time.
This lets you distinguish the cost of starting a database from the cost of using it. Closing the instance and final cleanup are outside the reported timers.
The PGlite speed-test suite
The full SQL workload runs the 16 historic cases published in PGlite's benchmark overview. This is a shared workload descended from SQLite and wa-sqlite, not a formal industry standard.
The unchanged SQL is pinned to upstream commit ae182ff8. Hashes and licenses accompany the downloadable SQL assets.
How it runs
Each complete SQL file goes into one PGlite exec call, in its original order. Every repetition starts with a fresh database. Fetching the SQL is outside the timers.
We omit the upstream live runner's additional 2.1 and 3.1 variants. Case 3.1 creates an index on a different table from the one it inserts into. The 16 included cases are unchanged.
How we check correctness
SELECT counts are checked after cases 4, 5, and 7. Before DROP, row counts and sums of both numeric columns and text lengths must match values independently calculated from the fixed SQL.
These checks are outside case timings. Total workload time is the sum of the 16 case timings. Only fully successful runs enter the comparison. Exports retain completed timings from failed or cancelled runs.
Cancel takes effect between SQL files, after the current file finishes. Cleanup then closes and removes that run's storage.
Durability settings
The PGlite durability option applies equally to all four backends. The benchmark's default waits for filesystem synchronization. OPFS VFS buffer and local durability settings are separate and affect only OPFS VFS.
Persistence timing is omitted in relaxed PGlite mode because its sync call can return before the filesystem write completes. Close and reopen still run, but closing time is outside the reported measurements.
We do not override PostgreSQL's synchronous_commit setting. Exports record the effective settings and workload revision.
New to these settings? The storage guide explains buffering and durability in plain language.
What stays constant
- SQL comparisons use the same PGlite version, schema, dataset, queries, and transaction boundaries.
- Filesystem comparisons use the same workload payload, repetitions, and storage options.
- Exports record the browser, isolation state, selected configuration, and failed or skipped samples.
Results from different hardware, browser versions, library versions, or durability settings are not directly interchangeable.
Reading the results
- Cold measurements do not mean browser or operating-system caches were cleared.
- An in-memory commit does not have the same persistence guarantee as a completed flush.
- A clean close and reopen does not test recovery from a crash or power loss.
- A skipped backend is not a zero.
The published comparisons include raw samples, environment details, and workload definitions. Mac results use five measured repetitions after one excluded warm-up and identify the base commit plus collector patch. The separate iPhone results use three measured runs, with no excluded full-workload warm-up recorded and no exact source commit available.
Tables show medians and observed minimum and maximum values. These ranges are not confidence intervals. Package version labels alone do not identify the tested source build.