Plate 48
Zod vs Valibot: 1.14M vs 0.97M Parses
zod 4.6.5 vs valibot 1.5.0 on one nested user schema (uuid/email/age/tags/profile/enum). Warm medians after 2k warmup + 9×50k: zod.parse 1,144,494 ops/s vs valibot.parse 968,187 (~1.18×). safeParse fail: valibot 697,760 vs zod 415,523 (~1.7×). esbuild minify+gzip9: 452,999/92,636 B vs 85,126/15,422 B. Package trees ~6.1 MB vs ~1.9 MB. Fixture /workspace/bench-zod-valibot/.
Aditya Challa4 min read
I parsed one nested user object 50,000 times per round on this box: Zod 4.6.5 median 1.14M ops/s on the success path, Valibot 1.5.0 median 0.97M ops/s — about 1.18× in Zod’s favor here. The same schemas minified to 453 KB vs 85 KB (gzip 93 KB vs 15 KB).
Short answer: keep Zod 4 if you already ship it and want the faster happy-path parse on this shape. Pick Valibot when the client bundle budget is the constraint. No affiliate links in this post.
What I tested
- Machine: 8 vCPU Intel Xeon / 15 GB RAM shared Linux cloud box, tested 6 Oct 2026 about 00:30–00:35 IST.
- Versions: zod 4.6.5, valibot 1.5.0, Node 22.20.0, esbuild for the bundle check.
- Fixture: /workspace/bench-zod-valibot/. One object schema (uuid, email, int age, tags array, nested profile, enum role). Good payload and a bad payload (bad email, negative age, invalid role).
- Timing: 2,000 warm iterations, then 9 rounds of 50,000 parse/safeParse calls each. Medians reported. Bundle: esbuild minify ESM browser build of
export { z } from "zod"vsexport * as v from "valibot", gzip -9. - Findings: zod.parse ok 1,144,494 ops/s (median 43.7 ms / 50k); valibot.parse ok 968,187 ops/s (51.6 ms). zod.safeParse ok 1,139,141; valibot.safeParse ok 979,417. On failures: valibot.safeParse 697,760 ops/s vs zod.safeParse 415,523 (~1.7× for Valibot). Package trees on disk: zod ~6.1 MB, valibot ~1.9 MB. Minify 452,999 B vs 85,126 B; gzip 92,636 B vs 15,422 B.
- One surprise: Zod 4 beat Valibot on the success path for this schema; Valibot still dominated fail-path throughput and the shipped bundle.
- Not tested: Zod codecs/transforms beyond this object, Valibot async pipes, TypeScript compile time, Deno/Bun, edge runtimes, schema codegen, Ajv.
How wide was the parse gap?
| Path | Median ops/s | Median ms / 50k |
|---|---|---|
| zod.parse ok | 1,144,494 | 43.7 |
| valibot.parse ok | 968,187 | 51.6 |
| zod.safeParse ok | 1,139,141 | 43.9 |
| valibot.safeParse ok | 979,417 | 51.1 |
| zod.safeParse fail | 415,523 | 120.3 |
| valibot.safeParse fail | 697,760 | 71.7 |
Same schema shape, same box. Happy-path parse favored Zod 4 here; invalid input favored Valibot. For lint/format cousins see Biome vs ESLint/Prettier and oxlint vs ESLint. For shipped JS weight, pair with size-limit vs bundlesize.
Does the bundle gap change the call?
Yes, if the schema library lands in the browser. Minified ESM was 453 KB for Zod vs 85 KB for Valibot; gzip -9 was 93 KB vs 15 KB (~6×). Installed package trees were ~6.1 MB vs ~1.9 MB. Server-only validation can ignore that; a form-heavy SPA should not.
Treat this as one object schema on Node 22, not a claim that Zod is always faster. Fail-path and bundle still lean Valibot.
Should you switch schema libraries?
| Situation | My pick |
|---|---|
| Already on Zod 4 in a Node API | Stay on Zod |
| Browser bundle is tight | Valibot |
| Heavy invalid-input traffic | Valibot (faster fail path here) |
| Need the Zod ecosystem (resolvers, partners) | Zod |
| Auditing unused deps after a swap | Pair with knip vs depcheck |
| Comparing test runners beside schema tests | See Jest vs Vitest |
Bottom line: on 50k parses of one user object, Zod 4.6.5 hit 1.14M ops/s median while Valibot 1.5.0 hit 0.97M, but Valibot shipped a 15 KB gzip bundle against Zod’s 93 KB. Who should not switch: teams whose Zod schemas and partner libs already pass CI.
How this was made: I installed zod and valibot on the ShopperCove box, timed interleaved parse rounds after a warm-up, measured esbuild minify+gzip sizes, recorded JSON; the write-up was drafted with AI help and checked against that output.
Sources
- https://zod.dev/
- https://www.npmjs.com/package/zod
- https://valibot.dev/
- https://www.npmjs.com/package/valibot
- https://github.com/colinhacks/zod
- https://github.com/fabian-hiller/valibot
Related
- https://www.shoppercove.com/blog/biome-vs-eslint-prettier
- https://www.shoppercove.com/blog/oxlint-vs-eslint
- https://www.shoppercove.com/blog/size-limit-vs-bundlesize
- https://www.shoppercove.com/blog/knip-vs-depcheck
- https://www.shoppercove.com/blog/jest-vs-vitest
- https://www.shoppercove.com/blog/dprint-vs-prettier
- https://www.shoppercove.com/blog/bun-test-vs-vitest
- https://www.shoppercove.com/blog/esbuild-register-vs-jiti
Lab evidence
What I found running this
Hands-on on ShopperCove box 6 Oct 2026 ~00:30–00:35 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). zod 4.6.5 vs valibot 1.5.0. Fixture /workspace/bench-zod-valibot/: one object schema (uuid, email, int age 0–120, tags[], nested profile, enum role); good + bad payloads. 2,000 warm iterations then 9 rounds × 50,000. Medians: zod.parse ok 1,144,494 ops/s (43.7 ms/50k); valibot.parse ok 968,187 (51.6 ms); zod.safeParse ok 1,139,141; valibot.safeParse ok 979,417; zod.safeParse fail 415,523; valibot.safeParse fail 697,760. Disk trees ~6.1 MB zod vs ~1.9 MB valibot. esbuild minify ESM: 452,999 B vs 85,126 B; gzip -9 92,636 B vs 15,422 B. Raw: /workspace/bench-zod-valibot/res-zod-valibot.json + res-bundle.json. Not tested: Ajv, async pipes, TS compile time, Deno/Bun, edge, schema codegen. No affiliate.