Context
Minimal bundle size became an explicit design goal for newer libraries in the TypeScript ecosystem, and Valibot is the most direct example of that in schema validation — born as a response to the weight of older libraries like Zod, even though today the two cover the same functional territory. The root of the difference is the basic unit of composition: Zod exposes a single schema builder: you start from z.object({...}) or a primitive schema like z.string() and chain methods (.min(), .optional()) on the same object. Valibot breaks each validation into an independent, separately importable function, combined explicitly through v.pipe(...) — there's no central object accumulating methods, there's a sequence of functions that pipe runs in order.
That granularity is Valibot's reason for existing: it was born after Zod, with a minimal bundle as a design goal from the start, betting that separating each validator into an isolated function lets modern builds strip out of the final bundle any validator the code doesn't explicitly import. The two, however, solve the same everyday set of problems — form validation, API payload parsing, environment variable checking — and produce structured error messages that can be mapped to whatever format the application needs.
When to choose Zod
Zod is the safer choice when the team wants the more mature ecosystem and the least integration friction — the vast majority of libraries that accept "a validation schema" as a parameter (forms, API type generation, schema tooling for agents) support Zod natively or as the most battle-tested option.
import { z } from "zod";
const Signup = z.object({
email: z.email(),
password: z.string().min(8),
});
Notice that z.email() above is already, by itself, a complete schema — it doesn't need to be wrapped in anything to be used as an email validator. That "single schema builder" format is the mental model most of the TypeScript ecosystem is already used to, which lowers the learning curve for anyone who has used any version of Zod before. The less favorable side is that, being a single, more established library, Zod has historically carried more code in the final bundle than an approach designed from the start for maximum granularity.
When to choose Valibot
Valibot makes sense when the weight of the validation bundle really matters — applications running on edge functions with package size limits, or frontends with a tight performance budget, where every KB of loaded JavaScript has a measurable cost:
import * as v from "valibot";
const Signup = v.object({
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
});
Unlike Zod's z.email(), the v.email() above is a validation action — it only exists inside a pipe(), never alone as a schema. That granularity is deliberate: since each validator is a separate function, a modern bundler can strip out of the final package any validator the code never imports, something harder to do when the validators are methods on a single schema object. The cost is verbosity — every string-format validation needs an explicit pipe() — and an ecosystem of integrations still growing, compared to Zod's already established coverage in the most widely used libraries. That verbosity is at least predictable: the pipe(type(), rule1(), rule2()) pattern repeats consistently across any string, number, or array validation, with no syntax exceptions to memorize case by case.
Verdict
The KB weight Valibot saves only pays off when someone actually measures the project's bundle budget — outside that specific scenario, the ecosystem maturity Zod has accumulated weighs more on the scale. If the team prioritizes the more mature ecosystem and integrations already tested in most popular libraries, and doesn't have a particularly tight bundle constraint, Zod is the option with the least friction. If the project runs in an environment sensitive to package size — edge functions, applications with a strict performance budget — and the team accepts the extra verbosity of composing each validation via pipe(), Valibot was designed exactly for that scenario.
The balance tends to shift on its own over time: as more libraries in the TypeScript ecosystem come to support Valibot natively, the maturity advantage that currently favors Zod gets smaller with each new integration — but that shift hasn't reached the scale Zod has already achieved.