Skip to main content
BlogWeb Dev

Valibot vs Zod: Bundle Size and Tree-Shaking

Valibot ships a schema in about 1.3 kB while Zod carries roughly 13 kB — here is why the modular pipe design tree-shakes and Zod's method chaining does not.

Matthews Wong

Software Engineer

July 20268 min read
Valibot vs Zod: Bundle Size and Tree-Shaking

Photo by Nikowsk via Wikimedia Commons (CC BY-SA 4.0)

Key Takeaway

For bundle-sensitive frontends and edge functions, Valibot beats Zod on size: Valibot v1 ships around 1.3 kB gzipped because its schema and validation functions are separate, tree-shakeable modules. Zod v4 standard bundles everything at roughly 13 kB; the new zod/v4-mini export trims that to about 3.9 kB, but Valibot's modular pipe design still wins.

I reach for Zod on almost every TypeScript project I run. It is the default for a reason: the API is comfortable, the type inference is excellent, and the ecosystem around it is enormous. But on a recent project I was shipping validation into a Cloudflare Worker and watching the bundle budget like a hawk, and Zod's weight became a real problem. That is when I started taking Valibot seriously, and the difference is not marginal.

The core question is not which library validates better. Both are correct, both infer types cleanly, both cover the same shapes. The question is what ends up in your production bundle, and that comes down to a single architectural decision each library made about how you compose a schema.

Why Zod's method chaining resists tree-shaking

Zod's classic API is method chaining on a single object. You import one thing and call methods off it. That ergonomic API is exactly what makes it hard to shrink. When you write the import below, the bundler pulls in the whole class graph because every method lives on the same object; a bundler cannot prove that you never call the string date parser or the discriminated union just because you did not type it here.

// Zod classic — one import, everything comes with it
import { z } from "zod";

const LoginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

type LoginData = z.infer<typeof LoginSchema>;
// The whole Zod runtime (~13 kB gzipped) is now in your bundle,
// even though this schema uses maybe five features.

This is not a flaw so much as a trade-off. Method chaining reads beautifully and it is the reason so many of us fell in love with Zod. But the object that carries all those methods is one indivisible unit as far as the bundler is concerned.

How Valibot's modular pipe design changes the math

Valibot inverts the design. Instead of methods on a class, every schema and every validation is a standalone function you import by name. Constraints are composed with a pipe function that threads a value through a sequence of actions. Because each action is its own exported function, the bundler keeps only the functions you actually reference and drops the rest. This is textbook tree-shaking, and it is why Valibot v1 lands around 1.3 kB gzipped for a typical schema.

// Valibot — import only the functions you name
import * as v from "valibot";

const LoginSchema = v.object({
  email: v.pipe(v.string(), v.email()),
  password: v.pipe(v.string(), v.minLength(8)),
});

type LoginData = v.InferOutput<typeof LoginSchema>;

// Parse the same way you would with Zod
const result = v.parse(LoginSchema, { email: "a@b.com", password: "secret12" });

The wildcard import (import star as v) looks like it pulls in everything, but it does not. Modern bundlers like esbuild, Rollup, and Rolldown resolve which named exports you actually use and shake out the rest. The namespace import is just an ergonomic convenience, not a bundle-size cost.

Zod v4 fought back with zod/v4-mini

Zod's maintainer clearly heard the bundle-size complaints. Zod v4, which landed in early 2025, introduced a separate zod/v4-mini export that abandons method chaining in favour of standalone check functions, much closer to Valibot's style. It brings the gzipped cost down to roughly 3.9 kB, a big improvement over the ~13 kB standard build. The catch is that the API is noticeably more verbose than classic Zod, and you give up some of the chaining ergonomics that made Zod pleasant in the first place.

// zod/v4-mini — standalone checks, no method chaining
import * as z from "zod/mini";

const LoginSchema = z.object({
  email: z.string().check(z.email()),
  password: z.string().check(z.minLength(8)),
});

type LoginData = z.infer<typeof LoginSchema>;
// ~3.9 kB gzipped — smaller than classic Zod,
// still roughly 3x heavier than Valibot for the same schema.

The comparison at a glance

DimensionValibot v1Zod v4 (classic / mini)
Gzipped size (typical schema)~1.3 kB~13 kB classic / ~3.9 kB mini
Composition modelStandalone functions + pipe()Method chaining / .check() in mini
Tree-shakeableYes, by designNo (classic) / Yes (mini)
API ergonomicsExplicit, more importsVery fluent (classic) / verbose (mini)
Ecosystem & adaptersGrowing, good but smallerHuge, de facto standard
Best fitEdge, browser, size-criticalNode servers, existing Zod code

Which one I actually pick

  • Server-side Node or NestJS APIs: I stay on Zod. Bundle size is irrelevant when the code runs on a long-lived server, and Zod's ecosystem, adapters, and familiarity win easily.
  • Cloudflare Workers, Vercel Edge, or anything with a cold-start and a size limit: Valibot, without hesitation. Shaving ten-plus kilobytes off every deploy matters when the platform caps you.
  • Client-side form validation in a browser bundle: Valibot if the page is performance-critical, otherwise either is fine.
  • A shared schema used on both frontend and backend: pick the one whose weight the frontend can tolerate, since the backend does not care either way.

Do not migrate a large existing Zod codebase to Valibot just to save kilobytes on the server. The refactor cost, the loss of Zod-specific adapters, and the risk of subtle validation differences almost never pay off unless bundle size is a hard, measured constraint. Measure first, then decide.

The honest summary: Valibot won the bundle-size argument so convincingly that Zod restructured its own API to answer it. That is the strongest endorsement Valibot could get. But Zod is not standing still, and for most server work its ergonomics and ecosystem still make it my default. Choose based on where the code runs, not on which library is trendier this quarter.

FAQ

Frequently Asked Questions

Short answers to what readers ask most about this topic.

Is Valibot really smaller than Zod?

Yes, and by a large margin for typical schemas. Valibot v1 lands around 1.3 kB gzipped because each schema and validation is a separate tree-shakeable function. Classic Zod v4 is roughly 13 kB because its method-chaining API bundles everything into one object, and even the newer zod/v4-mini export is about 3.9 kB.

Why can't Zod's classic API be tree-shaken?

Zod's classic API chains methods off a single object, so every validator lives on the same class. A bundler cannot prove you never call a given method just because it does not appear in your code, so it keeps the whole runtime. Valibot avoids this by making every validation a standalone exported function.

Does the wildcard import in Valibot pull in the whole library?

No. Writing an import-star-as-v statement looks like it imports everything, but modern bundlers such as esbuild, Rollup, and Rolldown analyse which named exports you actually reference and drop the rest. The namespace import is purely an ergonomic convenience with no bundle-size penalty.

Should I migrate my existing Zod code to Valibot?

Usually not, unless bundle size is a hard, measured constraint like an edge-function size limit. The refactor cost, the loss of Zod-specific adapters, and the risk of subtle validation differences rarely pay off on the server, where bundle size is irrelevant. Measure first, then decide.

What is zod/v4-mini and when should I use it?

zod/v4-mini is a tree-shakeable export introduced in Zod v4 that replaces method chaining with standalone check functions, bringing the gzipped cost down to roughly 3.9 kB. Use it when you want to stay in the Zod ecosystem but need a smaller bundle for the browser or edge. It is more verbose than classic Zod but still larger than Valibot.