zmdbzero-maintenance data layer
Docs Benchmarks Anti-patterns OpenAPI
Docs / Reference

Benchmarks

September 9 (Asia/Kolkata) refresh of zmdb and two selected peers per category, using the product after the latest performance fixes. HTTP covers Node, Bun and Deno. Both database comparisons use a freshly pulled PostgreSQL 18.6 image.

Capture boundaries

The tables rank only the selected participants, not every framework in the ecosystem. Timed captures run serially; each comparison uses the same resources for zmdb and its peers. p95 and p99 are shown where the runner records request or operation latencies. Validation's upstream throughput benchmark does not measure those percentiles.

The ORM fixture's projections and shared indexes were corrected before this replay. Earlier ORM numbers used unequal response shapes, and earlier HTTP captures used different CPU allocations; those historical values cannot establish a before/after speedup against this refresh.

Validation

zmdb registered as two participants in moltar/typescript-runtime-type-benchmarks and run by the upstream runner, one forked process per library, alongside the selected leaders ts-runtypes and ts-runtime-checks. zmdb is the runtime validator walking a descriptor; zmdb-aot is the same public API with the transformer applied, so the benchmarked code is transformer output rather than a hand-tuned lookalike.

Provenance & methodology
Upstream suitehttps://github.com/moltar/typescript-runtime-type-benchmarks
Grafted commit25a1d18491
Measured2026-09-08T23:21:01.408Z
Product revisiona86e01861b7609e8c3bc76aa9a1d85ced96cdb9f
Harness revisiond8534b48110dede2a9ab98898c524d276d59deb5
MachineAMD Ryzen 7 7840U w/ Radeon 780M Graphics
Runtimev26.8.1
LoadExisting upstream run-internal invoked once per selected library in isolated child processes. Existing benny/Benchmark.js defaults; prebuilt official generators; fixed upstream data; returned values discarded by upstream Benchmark.run. Throughput and upstream relative margin only; no p95/p99 or DCE-safe claim. CPU4. Selected peers: @ts-runtypes0.10.0 and ts-runtime-checks0.6.3; no other competitors were rerun.
⚠️ Read this before quoting a number

parseSafe is unsupported for zmdb and zmdb-aot: those APIs retain unknown properties instead of returning the stripped copy required by upstream. Historical numbers for those two cells are invalid and are not carried forward. Throughput uses a fixed input with discarded return values; this is not a per-call latency or dead-code-elimination-safe claim.

Raw samples and capture provenance

All four cases at once

The same numbers without a tab in the way — useful because a library can win one case and lose another, and the tabbed view makes that easy to miss.

A dash means the case is unsupported. zmdb and zmdb-aot are excluded from parseSafe: the upstream contract requires a copy with unknown properties removed, while these APIs validate and return the input. The upstream runner measures repeated calls on one fixed object and discards returned values. It provides throughput and error margins, not individual-call p95/p99 latency.

ORM HTTP replay

k6 replay over the upstream drizzle-team/drizzle-benchmarks 13-route request list, comparing zmdb, Drizzle and Kysely. The corrected fixture uses matching projections and response shapes, one shared dataset and index set, and the same PostgreSQL service, pg driver and connection-pool size for every participant.

Provenance & methodology
Upstream suitehttps://github.com/drizzle-team/drizzle-benchmarks
Grafted commit2ae27415a6
Measured2026-09-08T23:27:56.304499+00:00
Product revisiona86e01861b7609e8c3bc76aa9a1d85ced96cdb9f
Harness revisionc6269bedcebf222ee8372b8d9101a9fabaad2041
MachineAMD Ryzen 7 7840U w/ Radeon 780M Graphics
Databasepostgres (PostgreSQL) 18.6 (Debian 18.6-1.pgdg13+2); image digest sha256:7341002d2b8c7c5bdd7542a671a95b36196c0b5b888daf454ae4fc33ba5346d7
DatasetNorthwind:10,000 customers,200 employees,1,000 suppliers,5,000 products,50,000 orders,308,224 details
Driverpg8.23.0; shared pool size12; Drizzle0.45.2; Kysely0.29.5; Node26.8.1
LoadThree rotated passes per candidate,5s warmup then25s k6 ramp0→200→400VUs,426,999-entry upstream13-route request list. Server CPU4; k6 CPUs12-15; PostgreSQL CPUs6-11,memory2GiB,shm256MiB,default durability.
⚠️ Read this before quoting a number

Matching full projections and response shapes passed27 parity cases before timing. Both shared search GIN indexes are available to every participant. All rows use unprepared unnamed statements. These are short co-located, closed-loop runs without coordinated-omission correction; their request mixes depend on throughput. Historical projection-mismatched captures cannot establish a before/after speedup.

Raw samples and capture provenance

Route coverage

Throughput is only comparable between participants that answer the same routes. A participant that cannot express a route is marked missing here rather than being quietly dropped from the replay.

HTTP framework

Captured @zmdb/web and peer workloads under the the-benchmarker/web-frameworks shared contract — GET /, GET /user/:id, POST /user. zmdb runs on Node, Bun and Deno; the selected peers are Hono on Node and Deno, and Elysia on Bun. Each server uses one process on the same CPU.

Provenance & methodology
Upstream suitehttps://github.com/the-benchmarker/web-frameworks
Grafted commit2968d22c8d
Measured2026-09-08T23:48:19.553Z
Product revisiona86e01861b7609e8c3bc76aa9a1d85ced96cdb9f
Harness revisioned507604aa8d0cf67b93ddd5bb02d8729c50dd30
Peers measured2026-09-08T23:48:19.553Z
Machinelinux x64, 16× AMD Ryzen 7 7840U w/ Radeon 780M Graphics, 61 GiB, node v26.8.1
LoadThree rotated repetitions per candidate and each of the three published routes at c256; one server process on CPU4, oha on CPUs10,12,14, keepalive off. Each repetition has 1s warmup and 5s measurement. Saturation is closed-loop without coordinated-omission correction; fixed-rate uses -q20000 with --latency-correction. Each displayed row is the median-throughput repetition with its own percentiles. Other source builds, tests and benchmark captures were stopped during timing.
Peer loadThree rotated repetitions per candidate and each of the three published routes at c256; one server process on CPU4, oha on CPUs10,12,14, keepalive off. Each repetition has 1s warmup and 5s measurement. Saturation is closed-loop without coordinated-omission correction; fixed-rate uses -q20000 with --latency-correction. Each displayed row is the median-throughput repetition with its own percentiles. Other source builds, tests and benchmark captures were stopped during timing.
ContractEvery measured participant passed the three shared-route status/body checks before and after load.

Raw samples and capture provenance

Recorded runtimes: 3node v26.8.1: 1 worker, measured 2026-09-08T23:48:19.553Z; bun 1.4.0: 1 worker, measured 2026-09-08T23:48:19.553Z; deno deno 2.9.6 (stable, release, x86_64-unknown-linux-gnu) v8 15.0.245.2-rusty typescript 6.0.3: 1 worker, measured 2026-09-08T23:48:19.553Z.

Every candidate uses one server process, the same server CPU and separate load-generator CPUs. Saturation measures maximum throughput with closed-loop load; its latency is not coordinated-omission corrected. The fixed-rate capture offers 20,000 requests per second to every candidate and enables oha latency correction. Each displayed row keeps throughput and percentiles from the same median-throughput repetition. Brackets show the range of the three run summaries, not pooled percentiles or confidence intervals; raw downloads retain all repetitions.

Shared contract

Verified against every participant, ours included, before load is applied. A framework that fails this is not measured — a fast wrong answer is not a result.

MethodRouteStatusBodyVerified
GET/200yes
GET/user/:id20042 (for /user/42)yes
POST/user200yes

Repository and relation loading

Current generated schemas, the same PostgreSQL data and indexes, pg driver and pool of 12 connections. The nested workload returns 25 users, 100 posts and 300 comments. Kysely and the zmdb builder use three queries and the same assembler; repository and deferred loading use the public repository APIs. Native Drizzle uses one relational query with JSON aggregation. Result equality is checked before timing.

Provenance & methodology
Measured2026-09-08T23:35:00.608Z
Product revisiona86e01861b7609e8c3bc76aa9a1d85ced96cdb9f
Harness revision3c1c84dc5d1b5c41277f77983697dcaa8f660083
MachineAMD Ryzen 7 7840U w/ Radeon 780M Graphics
Runtimev26.8.1
Databasepostgres (PostgreSQL) 18.6 (Debian 18.6-1.pgdg13+2)
Driverpg8.23.0; pool12; Drizzle0.45.2; Kysely0.29.5
LoadDirect SQL-builder comparison uses each library to compile statements, then one common pg Pool transport and one common manual assembler. Repository/deferred lanes use the real BaseRepository. The separately labeled drizzle-relational strategy executes native findMany with one lateral JSON aggregation statement and its own result mapper through the same pool. Same selected columns and bound predicates; unordered graph equality is checked outside timing. All statements use the unprepared unnamed extended protocol. Trace timings are instrumented and excluded from clean ranking; roundtrip includes driver/network/server. Other time includes JS attachment, uninstrumented native relational compilation and async scheduling, not pure CPU. Three rotated rounds,1s warmup and4s measurement per cell; caller CPU4 and PostgreSQL CPUs6-11.

Raw samples and capture provenance

Each row is the median-throughput repetition with its own p95/p99, followed by the throughput range across all three repetitions. These are closed-loop client-operation latencies, without coordinated-omission correction.

lookup · 1 concurrent operations

Participantops/sp95 ms p99 msops/s range
zmdb-builder 16,764.710.07 0.116,584.09–17,017.8
kysely 16,437.340.07 0.116,435.35–16,555.82
repository 15,762.710.08 0.1215,657.91–16,432

nested · 1 concurrent operations

Participantops/sp95 ms p99 msops/s range
zmdb-builder 1,4640.92 1.071,443.91–1,515.76
kysely 1,463.130.92 1.081,424.86–1,517.76
repository 1,242.411.05 1.251,183.91–1,270.38
deferred 1,215.781.06 1.271,208.82–1,242.72
drizzle-relational 1,086.361.28 1.481,048.84–1,087.5

lookup · 48 concurrent operations

Participantops/sp95 ms p99 msops/s range
zmdb-builder 48,183.921.57 2.1747,721.75–48,284.18
kysely 44,505.021.68 2.0742,060.13–45,722.13
repository 41,179.51.88 2.2938,581.41–41,624.8

nested · 48 concurrent operations

Participantops/sp95 ms p99 msops/s range
zmdb-builder 2,930.7518.99 20.422,895.58–2,976.53
kysely 2,757.3220.38 22.482,683.63–2,801.26
repository 2,021.2627.14 29.072,020.42–2,085.94
drizzle-relational 1,882.2832.05 44.941,829.36–1,949.26
deferred 1,802.6330.73 34.671,746.77–1,829.17

Latest optimizations — 9 September 2026 (Asia/Kolkata)

Before/after measurements of the changes integrated in 4c9cf2f4, using 9c8c206f as the baseline. These short, sequential runs compare zmdb with itself. They do not update competitor rankings or establish an industry-wide lead.

AMD Ryzen 7 7840U; Node 26.8.1, Bun 1.4.0, Deno 2.9.6; project compiler TypeScript 7.0.2; PostgreSQL 18.6, pg 8.23.0; oha 1.16.0. One application process on logical CPU 4. Timed runs were sequential with no concurrent owned builds or tests; ordinary desktop services remained running.

Values in brackets are observed sample ranges, not confidence intervals. The p99 columns show ranges of individual run percentiles; they are not pooled percentiles.

Serialization and generated validation

Five 80 ms samples per case and version, alternating order after 150 ms warmup, using the same 32 rotating inputs and consumed outputs. Lower time is better. These are the actual generated predicates and public serializer; no peer implementation was loaded.

Workload Before (median ns/op)After (median ns/op) Time reduction
Numeric validation: valid20.46 [20.43–21.06] 19.61 [19.3–20.39]+4.13%
Numeric validation: late invalid20.21 [19.76–20.38] 19.76 [19.14–21.33]+2.27%
Strict validation: valid34.1 [33.33–34.5] 34.16 [32.6–41.86]-0.19%
Strict validation: excess property33.61 [32.77–35.36] 33.12 [31.76–37.91]+1.47%
JSON: plain strings1,199.19 [1,109.37–1,347.7] 534.18 [490.79–616.34]+55.46%
JSON: escaped strings1,499.54 [1,401.27–1,520.13] 710.33 [659.71–816.85]+52.63%

Native serialization took 53–55% less time on these inputs. Numeric-validation differences were small and several sample ranges overlap; no general validator speedup is established.

HTTP and request data

Two four-second samples per version after one-second warmup, in before/after/after/before order, at 64 connections with keep-alive. One server process on CPU 4; client on CPUs 10, 12 and 14. Closed-loop maximum throughput; latency is not coordinated-omission corrected.

Workload Before (mean req/s)After (mean req/s) Throughput changeBefore p99 (ms)After p99 (ms)
Node POST validation39,326.86 [36,328.05–42,325.67] 43,298.56 [41,769.06–44,828.05]+10.1% 4.25–5.223.28–3.76
Bun POST validation42,862.17 [42,614.35–43,109.99] 45,274.44 [43,365.94–47,182.95]+5.63% 2.88–3.152.54–3
Deno POST validation51,406.19 [50,746.64–52,065.74] 61,561.37 [60,167.55–62,955.19]+19.75% 4.76–4.894.16–4.51
Deno GET parameter78,532.97 [77,607.8–79,458.15] 93,252.92 [91,542.56–94,963.29]+18.74% 2.06–2.121.64–1.75

These results combine Fetch header/response conversion and the shared lazy request-data getter; their individual contributions are not isolated. Node throughput ranges and Bun p99 ranges overlap. The bounded request-body reader is unchanged.

Nested relation loading

Two four-second samples per version after one-second warmup, in before/after/after/before order, at concurrency 48 with a 12-connection pg pool. Each read returns 25 users, 100 posts and 300 comments in three queries. Medians of two samples are their midpoint. PostgreSQL runs on CPUs 6–11 on the same machine.

Workload Before (median operations/s)After (median operations/s) Throughput changeBefore p99 (ms)After p99 (ms)
Nested repository1,425.94 [1,403.86–1,448.02] 1,572.69 [1,512.89–1,632.5]+10.29% 60.54–74.7763.92–70.51
Deferred nested loading1,409.09 [1,403.03–1,415.14] 1,488.57 [1,370.15–1,607]+5.64% 62.24–63.8540.84–68.98

Repository throughput increased about 10% in this probe. Deferred results were more variable, and neither lane establishes a consistent p99 improvement.

Database comparison fairness

The corrected 13-route ORM fixture uses matching projections, response structures, data, driver and pool settings across zmdb, Drizzle and Kysely. Both full-text GIN indexes are created by the shared seed and are available to every participant. All 27 functional response-parity cases passed, and PostgreSQL selected both indexes. This is a correctness result, not a newly measured peer ranking.

Summary and provenance (JSON) · Per-run measurements and source hashes (gzip JSON) · Earlier comparative benchmarks and profiling report

The linked investigation measured revision 07b3ec80 before these optimizations. Its peer comparisons and experimental ablations retain their original conditions; experimental gains are not substituted for the implemented measurements above.

Engineering costs — earlier capture

Recorded zmdb measurements at revision cd6cdcc965a38d6ddc5b40a91b30f2f66bde4571. Each row uses the committed metric name, unit, median and min–max range. Values are displayed to three decimal places; full precision and every sample are available in the downloads.

Capture2026-09-08T12:00:09.163Z → 2026-09-08T12:08:20.206Z
Node / npm / Yarnv26.8.1 / 12.0.2 / 4.18.0
TypeScript / SQLite7.0.2 / 3.53.4
PostgreSQLPostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
Load generatork6 v2.2.0 (commit/00a9a1b7f5, go1.26.5, linux/amd64)
Platformlinux 7.1.8-gentoo x64
CPUAMD Ryzen 7 7840U w/ Radeon 780M Graphics (16 logical CPUs)
Memory65,044,914,176 bytes
Initial load average1.93, 5.03, 3.35
Rounds7

Repeated current-revision zmdb measurements. Every sample is retained; summaries report median and range. Clean build means no emitted output; cached build retains filesystem/dependency caches. OS caches are not flushed. Compiler and installation tools are included in consumer size. PostgreSQL and load generator share this machine. No competitor reruns or comparative ranking.

OS caches are warm or unflushed, including clean-build runs; this capture does not measure a cold OS cache. PostgreSQL and the load generator are co-located. These zmdb-only results are separate from the historical competitor, PostgreSQL 16, Bun and Deno measurements below.

Summary and per-metric samples (JSON) · Complete raw runs and command output (gzip JSON) · Aggregation and metric definitions

Editor and compiler

Public product and server-core consumer projects: language-service operations and clean, incremental and affected-edit compilation. Measurement source.

MetricUnitSamples MedianMin–max
editor/consumer-product/loadms 7302.748 283.341320.011
editor/consumer-product/diagnosticsms 73.733 3.6123.997
editor/consumer-product/completionms 71.813 1.6662.581
editor/consumer-product/quickInfoms 72.406 2.1722.886
editor/consumer-product/edit-and-diagnosticsms 73.419 2.8254.142
editor/consumer-product/undo-and-diagnosticsms 72.626 2.1534.108
compiler/consumer-product/cleanms 7385.64 363.161389.522
compiler/consumer-product/incrementalms 778.666 75.8583.303
compiler/consumer-product/affected-editms 796.272 93.52106.009
editor/consumer-server-core/loadms 7290.54 276.926337.389
editor/consumer-server-core/diagnosticsms 71.888 1.8552.083
editor/consumer-server-core/completionms 71.331 1.2361.812
editor/consumer-server-core/quickInfoms 71.509 1.3431.806
editor/consumer-server-core/edit-and-diagnosticsms 72.823 2.5163.046
editor/consumer-server-core/undo-and-diagnosticsms 72.368 1.9012.704
compiler/consumer-server-core/cleanms 7213.454 207.274249.67
compiler/consumer-server-core/incrementalms 756.84 55.17460.577
compiler/consumer-server-core/affected-editms 779.76 77.48387.144

Build, package and consumer

Clean builds remove emitted output; cached builds repeat the same build command with filesystem and dependency caches retained. Installed size and package count include TypeScript and installation tooling. Measurement source.

MetricUnitSamples MedianMin–max
build/cleanms 76,613.607 6,294.8416,791.917
build/cachedms 76,628.487 6,362.7716,703.697
package/pack-required-closurems 74,546.847 4,439.1984,596.987
package/archive-sizebytes 72,491,144 2,491,1442,491,144
consumer/installMsms 76,070.039 5,366.7846,354.656
consumer/importMsms 781.447 76.67383.763
consumer/typecheckAndEmitMsms 7380.582 369.229391.566
consumer/processMsms 7151.191 149.722154.255
consumer/installed-size-with-typescriptbytes 772,500,531 72,500,53172,500,531
consumer/installed-package-count-with-typescriptcount 721 2121

Startup and first work

Separate application initialization, process readiness, first HTTP request, first application query through SQLite and shutdown intervals. Measurement source.

MetricUnitSamples MedianMin–max
startup/applicationInitMsms 70.115 0.1020.12
startup/processToReadinessMsms 7124.036 122.7127.135
startup/firstHttpMsms 716.613 16.10717.06
startup/firstApplicationQueryMsms 70.408 0.3970.515
startup/shutdownMsms 70.829 0.8020.857

PostgreSQL replay

zmdb-only HTTP replay. Latency medians and p90/p95/p99 rows are medians of per-run percentiles; they are not percentiles of a pooled request distribution. The range is the minimum and maximum run summary. Measurement source.

MetricUnitSamples MedianMin–max
postgres/requests-per-secondreq/s 73,690.018 3,625.1363,715.487
postgres/latency-avgms 780.79 80.3482.396
postgres/latency-medms 789.813 89.24891.072
postgres/latency-p(90)ms 7118.105 117.407120.263
postgres/latency-p(95)ms 7126.806 125.976129.723
postgres/latency-p(99)ms 7156.108 151.042158.424

Reproduce this workload

Use an idle machine, a fresh work directory outside the repository, an installed k6 executable and a PostgreSQL server seeded with the Northwind loader. The capture records: node benchmarks/scripts/baseline.mjs --work-dir <outside-workspace> --rounds 7 (K6 and PGURL must identify the load generator and seeded PostgreSQL server).

K6=/absolute/path/to/k6 PGURL='postgres://user:password@localhost:55432/bench' \
  node benchmarks/scripts/baseline.mjs --work-dir ../zmdb-engineering-run --rounds 7
node --import ./scripts/ts-specifier-hook.mjs docs-site/build.mjs

The baseline script invokes the linked editor/compiler, lifecycle and PostgreSQL workloads and retains all rounds. The docs build renders the committed files. See the reproduction guide for setup and individual diagnostic commands.

Raw data: validation.json · orm.json · framework.json · repository.json · Fresh peer comparison samples and provenance · orm-results.json · framework-results.json (node) · framework-results-bun.json · framework-results-deno.json · peers-results.json · interleaved-results.json · interleaved-measurements.csv (every individual measurement, with the CPU clock it was taken at) · validation-matrix.json (standalone harness cross-check)