Zod Won the TypeScript Validation War
Itβs 2026 and the debate is effectively over. Zod has become the default schema validation library for TypeScript projects. From tRPC to Next.js server actions to Astro content collections, Zod is baked into the tools developers reach for every day. Yup still works β and still has valid use cases β but the momentum is undeniable.
This post breaks down exactly where each library stands, with code examples, performance notes, and guidance on when each one still makes sense.
Feature Comparison
| Feature | Zod | Yup |
|---|---|---|
| Language focus | TypeScript-first | JavaScript-first |
| Type inference | z.infer<typeof schema> | Manual type definitions |
| Bundle size (min+gzip) | ~13KB | ~15KB |
| API style | Strict, chainable | Flexible, chainable |
| Default behavior | Strict (no unknown keys) | Permissive (strips unknown) |
| Async validation | Supported | Supported |
| Custom error messages | Per-field, per-rule | Per-field, per-rule |
| Transforms | Built-in .transform() | Built-in .transform() |
| Discriminated unions | Native z.discriminatedUnion() | Manual workarounds |
| Recursive schemas | z.lazy() | yup.lazy() |
| Ecosystem adoption | tRPC, Next.js, Astro, React Hook Form | Formik, older React projects |
| First release | 2020 | 2014 |
TypeScript Integration
This is where Zod pulls ahead decisively. Zod was designed so that your schema is your type. You define validation once and infer the TypeScript type directly from it:
import { z } from "zod";
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive(),
});
// Type is inferred automatically β no duplication
type User = z.infer<typeof UserSchema>;
With Yup, you typically end up maintaining a separate interface alongside your schema:
import * as yup from "yup";
// You need this separately
interface User {
name: string;
email: string;
age: number;
}
const UserSchema = yup.object({
name: yup.string().required(),
email: yup.string().email().required(),
age: yup.number().positive().integer().required(),
});
The duplication isnβt just annoying β itβs a source of bugs. When you change the schema but forget to update the interface, TypeScript wonβt catch the mismatch. With Zod, that entire category of bug disappears.
API Design Comparison
Both libraries use chainable APIs, but Zodβs defaults are stricter. Zod treats fields as required by default and rejects unknown keys. Yup treats fields as optional unless you call .required() and silently strips unknown keys.
Zod approach for a REST API request body:
const CreatePostSchema = z.object({
title: z.string().min(1).max(200),
body: z.string().min(10),
published: z.boolean().default(false),
tags: z.array(z.string()).optional(),
});
// Parsing throws on invalid data
const result = CreatePostSchema.safeParse(requestBody);
if (!result.success) {
console.error(result.error.flatten());
}
Yup equivalent:
const CreatePostSchema = yup.object({
title: yup.string().required().min(1).max(200),
body: yup.string().required().min(10),
published: yup.boolean().default(false),
tags: yup.array().of(yup.string()),
});
// Validation throws or returns
try {
const data = await CreatePostSchema.validate(requestBody);
} catch (err) {
console.error(err.errors);
}
Zodβs safeParse returns a discriminated union β either { success: true, data } or { success: false, error } β which is more ergonomic in TypeScript than try/catch patterns.
Performance
Both libraries are fast enough for virtually all real-world use cases. Benchmarks show Zod and Yup performing within the same ballpark for typical object validation. If youβre validating thousands of objects per second in a hot loop, youβd look at something like Typia or compiled validators anyway.
For form validation, API route handlers, and content schemas, neither library will be your bottleneck. Pick based on developer experience, not microseconds.
Ecosystem
This is where Zodβs dominance becomes clear:
- tRPC β Zod is the default input validator. See our tRPC vs GraphQL comparison for context.
- Next.js Server Actions β Zod is the recommended validation layer in the official docs.
- Astro Content Collections β uses Zod schemas to define and validate frontmatter.
- React Hook Form β the
@hookform/resolverspackage supports both, but Zod examples dominate the docs. - Nuxt β server routes commonly use Zod via H3 validation.
- Conform β React form library built around Zod schemas.
Yup still has strong integration with Formik, which remains popular in legacy React codebases. If your project already uses Formik + Yup, thereβs no urgent reason to migrate.
When to Use Zod
- New TypeScript projects of any size
- You want a single source of truth for types and validation
- Youβre using tRPC, Next.js, or Astro
- You want strict defaults that catch bugs early
- You need discriminated unions or complex schema composition
- Check our Zod cheat sheet for a quick reference
When to Use Yup
- Existing projects with Yup already integrated
- Formik-based forms where migration cost isnβt justified
- JavaScript-only projects (no TypeScript)
- Teams that prefer permissive validation defaults
Verdict
Zod is the clear default for new TypeScript projects in 2026. The type inference via z.infer<> eliminates an entire class of bugs, the ecosystem has standardized around it, and the strict-by-default API catches issues earlier. If youβre starting fresh, use Zod.
Yup remains a solid library with no critical flaws. If itβs already in your codebase and working well, a migration isnβt mandatory. But for greenfield work, Zod is the answer.
FAQ
Is Zod better than Yup?
For TypeScript projects, yes. Zodβs type inference via z.infer<> eliminates the need to maintain separate type definitions, and its strict-by-default API catches more bugs at validation time. Yup is still a solid library but lacks the tight TypeScript integration that modern projects demand.
Can I use Zod without TypeScript?
Yes β Zod works in plain JavaScript projects. However, you lose the main advantage (automatic type inference), so the benefit over Yup diminishes significantly in a JavaScript-only codebase.
Is Yup still maintained?
Yes, Yup is still actively maintained and receives updates. It remains a reliable choice for existing projects, especially those using Formik. However, its pace of development and ecosystem adoption has slowed compared to Zod.
Which validation library should I use with React Hook Form?
Both work via @hookform/resolvers, but Zod is the recommended choice. React Hook Formβs documentation and examples predominantly feature Zod, and the type inference means your form types stay in sync with validation rules automatically.