Numbers with a gate attached.
Performance claims are only interesting when they are reproducible and enforced. These figures ship with a suite that runs in CI against the latest stable Zod, and the harness is in the repository for you to run unchanged.
- Ten scenarios covering strings, numbers, nullish, optional, unions, arrays and objects.
- One million safeParse operations per scenario, twenty-one runs, warm-up discarded.
- Every result is semantic-checked — a fast wrong answer fails the gate.
- Enforced in CI on every commit, so a regression cannot be merged quietly.
higher is better
V2 method memoization vs V1 vs Zod
lower is better · 1M safeParse
| schema | VLD V1 | VLD V2 | Zod | V2 vs Zod |
|---|---|---|---|---|
| string().min(1).email() | 22ms | 22ms | 50ms | 2.3× faster |
| number().int().positive() | 12ms | 6ms | 39ms | 6.5× faster |
| object({ a: str, b: num }) | 12ms | 11ms | 18ms | 1.6× faster |
| realistic API (10 fields) | 276ms | 243ms | 767ms | 3.2× faster |
Run the head-to-head yourself.
This builds the same nine-field schema twice — once with @oxog/vld, once with the published zod you have on disk — then checks that both agree on a valid and an invalid payload before timing them.
- id: uuid
- name: string().min(2).max(100)
- email: email
- age: int().min(18).max(120)
- score: number().min(0).max(1000)
- role: enum(admin,user,guest)
- tags: array(string).min(1)
- active: boolean
- url: url
100,000 safeParse calls per library, best of five runs. A single schema on a single machine is not a benchmark suite — treat the ratio as an indication, and reproduce the full suite locally.
Press run. Zod is fetched only at this moment, so it costs the page nothing until you ask for it.
# the official suite, gated against the latest stable Zodnpm run benchmark # fail the build if a performance floor is missednpm run benchmark:guard # allocation and retention per schema shapenpm run benchmark:memory # cold-start cost of importing the packagenpm run benchmark:startup # the full release gate: tests, parity, exports, performancenpm run release:checkHow to read these numbers
A validator's cost is dominated by shape complexity, not by the library's overhead alone. The 620M ops/sec figure is a single string check with one constraint; the object and array cases sit near 49M ops/sec because they allocate output objects.
The meaningful comparison is always per-scenario and against the same baseline. That is why the CI gate fails on a regression in any scenario rather than on the average.
Your hardware, Node version and payload shape will move these numbers. The reproduction commands above run the identical harness, and the benchmark sources are plain Node scripts with no framework.