Zod v4 is a major overhaul of the most popular TypeScript schema validation library — delivering 14x faster string parsing, a 57% smaller core bundle, and a completely reworked API for format validation. Most codebases can migrate in under a day using the official codemod, but there are real breaking changes that will catch you off guard if you skip the changelog.
What Is Zod v4 and Why the Major Version Bump?
Zod v4 is a ground-up rewrite of Zod’s internal architecture, released by Colin McDonnell in mid-2025 after two years of development driven by feedback from Zod v3’s performance and bundle size limitations. With over 42,835 GitHub stars and 102 million weekly npm downloads, Zod is the de facto TypeScript runtime validation standard — and v4 is the release that finally addresses the criticisms Valibot raised in 2023. The major version bump is justified: v4 ships real breaking changes to string format methods, object strictness options, and error handling. But beyond compatibility breaks, v4 introduces architectural changes — a new zod/v4/core sub-package, the @zod/mini tree-shakable distribution, a metadata registry system, and first-class JSON Schema conversion — that change what you can build with Zod. This isn’t just a performance patch; it’s a new foundation for the library’s next five years.
Why the Breaking Changes Were Necessary
The Zod v3 API accumulated technical debt around how string format validators were attached to the z.string() chain. Methods like .email(), .uuid(), .url(), and .ip() were implemented as string refinements, which blocked tree-shaking and forced all format logic into the core bundle even for schemas that never use email validation. Moving these to top-level functions (z.email(), z.uuid()) was the only architecturally sound path to enabling the @zod/mini 1.9 KB distribution.
Performance Improvements — 14x Faster Parsing and a 57% Smaller Bundle
Zod v4 is dramatically faster than v3 across all primitive types: 14x faster string parsing, 7x faster array parsing, and 6.5x faster object parsing, according to official benchmarks from the Zod v4 release page. On a realistic 50+ field schema parsing 1,000 objects, the improvement reaches 100x — dropping from 480ms in v3 to 4.8ms in v4. The core bundle is 57% smaller (2.3x), and TypeScript compile-time performance improves by up to 10x on large codebases. These numbers come from a complete rewrite of the parsing engine, which eliminated redundant type-checking layers, replaced recursive traversal with iterative loops, and pushed format validation out of the hot path. For most production applications, the cold-start and hot-path latency improvements will be noticeable immediately after upgrading. The smaller bundle also means less JavaScript for browsers to parse and execute, directly improving frontend performance metrics.
What Drives the Speed Gains
Three architectural decisions explain the performance jump:
- Eliminated double validation: v3 ran type checks twice in some paths; v4 does a single pass.
- Iterative instead of recursive: deeply nested schemas no longer risk stack overflows, and iterative traversal is faster in V8.
- Lazy format validation:
z.string()no longer bundles email/url/uuid logic unless you explicitly importz.email().
Breaking Changes You Must Know Before Migrating
Zod v4 ships seven categories of breaking changes that will cause runtime errors or type errors if not addressed. The most impactful changes are: string format methods removed from z.string() chain, object strictness helpers deprecated, and ZodError constructor unified. Before touching your codebase, run npx zod-v3-to-v4 to catch the machine-fixable issues automatically.
String format methods moved to top-level functions:
// Zod v3
const emailSchema = z.string().email();
const urlSchema = z.string().url();
const uuidSchema = z.string().uuid();
// Zod v4
const emailSchema = z.email();
const urlSchema = z.url();
const uuidSchema = z.uuid();
Object strictness methods deprecated:
// Zod v3
const schema = z.object({ name: z.string() }).strict();
const schema2 = z.object({ name: z.string() }).passthrough();
// Zod v4
const schema = z.strictObject({ name: z.string() });
const schema2 = z.looseObject({ name: z.string() });
Error handling unified — single parameter for custom errors:
// Zod v3
z.string().min(3, { message: "Too short" });
// Zod v4
z.string().min(3, "Too short"); // string shorthand works
z.string().min(3, { error: "Too short" }); // 'message' → 'error'
z.discriminatedUnion() requires literal discriminators — computed or template literal discriminators from v3 will need refactoring.
ZodError.issues path format changed for nested arrays — update any custom error display logic that walks issue paths.
Breaking Change Impact by Project Type
| Project Type | Most-Affected APIs | Risk Level |
|---|---|---|
| Form validation (react-hook-form) | .email(), .url(), error messages | Medium |
| API validation (Express/Fastify) | .strict(), discriminatedUnion | Medium |
| OpenAPI/tRPC schemas | Nearly all, but codemod covers most | Low-Medium |
| CLI tools | Object strictness | Low |
| Frontend-only (switching to @zod/mini) | Full API surface | High |
New Features in Zod v4 — What You Actually Gain
Zod v4 adds capabilities that were impossible or impractical in v3: template literal type schemas, bidirectional JSON Schema conversion, a metadata registry, prettified error output, and the @zod/mini lightweight distribution. Template literal schemas (z.templateLiteral) let you validate strings like "event:${string}" with full TypeScript type inference — a feature previously only available in libraries like ArkType. JSON Schema conversion (z.toJSONSchema() / z.fromJSONSchema()) enables Zod to serve as the source of truth for OpenAPI specs without a separate schema definition layer. The metadata system (z.globalRegistry) lets you attach arbitrary metadata — descriptions, examples, deprecation flags — to any schema and access it at runtime. These aren’t minor additions; they close the gap between Zod and more specialized validation tools for API contract workflows.
New Error Formatting API
// Prettified errors — human-readable output for debugging
const result = z.object({ name: z.string(), age: z.number() }).safeParse({ name: 123, age: "old" });
if (!result.success) {
console.log(z.prettifyError(result.error));
// ✕ name: Expected string, received number
// ✕ age: Expected number, received string
}
Template Literal Types
// Match "event:click", "event:hover", etc. with full type safety
const eventSchema = z.templateLiteral(["event:", z.string()]);
type Event = z.infer<typeof eventSchema>; // `event:${string}`
JSON Schema Round-Trip
import { z } from "zod";
const userSchema = z.object({
id: z.uuid(),
email: z.email(),
age: z.number().int().min(0).max(150)
});
const jsonSchema = z.toJSONSchema(userSchema);
// { type: "object", properties: { id: { type: "string", format: "uuid" }, ... } }
// And back
const recovered = z.fromJSONSchema(jsonSchema);
@zod/mini — The Lightweight 1.9 KB Gzipped Distribution
@zod/mini is a separate npm package providing a tree-shakable subset of Zod v4 that weighs approximately 1.9 KB gzipped — compared to the full Zod v4 core which, while 57% smaller than v3, still ships more validation infrastructure than frontend bundles typically need. The package shares internal implementation with Zod v4 via the zod/v4/core sub-package, so it’s not a fork — schemas created with @zod/mini are fully compatible with Zod v4 schemas at the type level. The API difference is that @zod/mini replaces method-chaining refinements with standalone function wrappers: instead of z.string().min(3), you write z.string(z.minLength(3)). This change is what enables proper tree-shaking in bundlers, since each validation function is a discrete import that dead-code elimination can remove. For frontend applications that currently import the full Zod package just for form validation, switching to @zod/mini can meaningfully reduce bundle sizes.
@zod/mini API Pattern
import { z } from "@zod/mini";
// @zod/mini uses function composition instead of method chaining
const emailSchema = z.string(z.email(), z.maxLength(100));
const userSchema = z.object({
email: emailSchema,
age: z.number(z.int(), z.gte(0), z.lte(150))
});
Zod vs @zod/mini vs Valibot Bundle Size
| Library | Bundle (gzipped) | API Style | TypeScript Inference |
|---|---|---|---|
| Zod v3 | ~14 KB | Method chain | Full |
| Zod v4 core | ~6 KB | Method chain | Full |
| @zod/mini | ~1.9 KB | Function composition | Full |
| Valibot (simple form) | ~1.4 KB | Function composition | Full |
Step-by-Step Migration Guide from Zod v3 to v4
Migrating from Zod v3 to v4 takes most projects under a day. The recommended sequence is: run the codemod first, fix TypeScript errors, then test your error handling paths. Start by installing Zod v4 — it’s still published to the zod package, so npm install zod@^4.0.0 is the only installation step. The codemod handles the highest-volume changes (string format methods, object strictness methods) automatically. Manual work is limited to: custom error message keys (message → error), any code that directly constructs ZodError objects, and custom discriminated union patterns that relied on non-literal discriminators.
Step 1 — Update the package:
npm install zod@^4.0.0
# or
yarn add zod@^4.0.0
# or
pnpm add zod@^4.0.0
Step 2 — Run the codemod:
npx zod-v3-to-v4
Step 3 — Fix remaining TypeScript errors:
After the codemod, run tsc --noEmit and address any remaining type errors. Common remaining issues:
- Custom
ZodErrorconstruction — update to new constructor signature z.discriminatedUnion()with non-literal discriminators — replace with union + refinement.superRefine()callback signature changes — second parameter is now a context object
Step 4 — Update error message keys:
// Search-replace: message: → error: in Zod option objects
// Before
z.string().min(1, { message: "Required" })
// After
z.string().min(1, { error: "Required" })
Step 5 — Test error paths:
Run your form submission tests and API validation tests with invalid inputs. Zod v4 formats errors differently in some edge cases — snapshot tests on error shapes may need updating.
Using the zod-v3-to-v4 Automated Codemod
The zod-v3-to-v4 codemod is the fastest path through the mechanical parts of the Zod v4 migration. It uses jscodeshift to perform AST-level transforms — not regex substitution — so it handles complex cases like chained method calls inside ternaries, destructured schema assignments, and re-exported schemas correctly. Run it with npx zod-v3-to-v4 from your project root; it automatically scans src/ and lib/ directories. The --dry-run flag prints what would change without modifying files, useful for reviewing scope before committing. The codemod covers: .email() → z.email(), .url() → z.url(), .uuid() → z.uuid(), .ip() → z.ip(), .cuid() → z.cuid(), .nanoid() → z.nanoid(), .strict() → z.strictObject(), .passthrough() → z.looseObject(), and .strip() → z.object(). It does NOT cover: message → error key renames in option objects, discriminated union discriminator changes, or custom error class construction.
# Dry run first
npx zod-v3-to-v4 --dry-run
# Apply to src directory
npx zod-v3-to-v4 src/
# Apply to all TypeScript files in project
npx zod-v3-to-v4 --extensions=ts,tsx
What the Codemod Transforms (and What It Doesn’t)
| Transform | Codemod Handles | Manual Required |
|---|---|---|
.email() → z.email() | Yes | No |
.url() → z.url() | Yes | No |
.uuid() → z.uuid() | Yes | No |
.strict() → z.strictObject() | Yes | No |
.passthrough() → z.looseObject() | Yes | No |
message: → error: in options | No | Yes |
| Discriminated union discriminators | No | Yes |
ZodError constructor changes | No | Yes |
Zod v4 vs Valibot and ArkType — Which Should You Choose?
Zod v4 is the right choice for most TypeScript projects in 2026, but it’s not the universal answer. Valibot remains meaningfully smaller for simple frontend schemas — a basic login form validation with Valibot is still ~90% smaller than Zod standard and ~73% smaller than Zod Mini, according to benchmarks from pkgpulse.com. ArkType offers the most advanced type inference in the ecosystem, supporting runtime-defined types with TypeScript-level fidelity that Zod’s structural approach can’t match. The practical decision comes down to three variables: bundle budget, ecosystem integration (tRPC, react-hook-form, Prisma, OpenAPI generators all have Zod adapters), and team familiarity. For any project already using Zod v3, upgrading to v4 is the obvious call. For greenfield frontend-only projects with strict bundle constraints, Valibot is worth evaluating. For complex domain type modeling where correctness matters more than ecosystem breadth, ArkType is the specialist choice.
Feature Comparison 2026
| Feature | Zod v4 | @zod/mini | Valibot | ArkType |
|---|---|---|---|---|
| Bundle size (gzipped) | ~6 KB | ~1.9 KB | ~1.4 KB | ~5 KB |
| Method chaining | Yes | No | No | No |
| JSON Schema output | Built-in | Built-in | Plugin | Plugin |
| Template literal types | Yes | Yes | No | Yes |
| tRPC integration | Native | Partial | Via adapter | Via adapter |
| TypeScript inference quality | Excellent | Excellent | Excellent | Best-in-class |
| Codemod available | v3→v4 | — | — | — |
Should You Upgrade Now? — Practical Decision Framework
Upgrading to Zod v4 makes sense for the vast majority of Zod v3 users, but the timing depends on your dependency chain. As of June 2026, most major Zod consumers — tRPC, Prisma, react-hook-form resolvers, and popular OpenAPI generators — have released Zod v4 compatible versions. If you’re on a well-maintained dependency stack and not on an extremely old Node.js version (Zod v4 requires Node 16+), the upgrade path is low-risk. The main reason to delay is if your project has deep integrations with third-party libraries that haven’t yet published Zod v4 support — check their issue trackers before upgrading. The performance gains are real and not marginal: if you’re doing server-side validation on high-traffic routes, the 7–14x speedup translates directly to lower latency and reduced compute costs. For frontend projects, the smaller bundle is valuable even before reaching @zod/mini. The breaking changes are real but manageable — run the codemod, budget two to four hours for manual fixes, and test your error handling paths.
Upgrade Decision Matrix
| Your Situation | Recommendation |
|---|---|
| Zod v3 on active project, no unusual dependencies | Upgrade now |
| Zod v3 on project with custom ZodError handling | Upgrade, budget 4h for manual work |
| Zod v3 with niche third-party Zod adapters | Check adapter compatibility first |
| New project starting fresh | Use Zod v4 from day one |
| Frontend-only, bundle size critical | Evaluate @zod/mini or Valibot |
| Node 14 or earlier | Stay on v3 or upgrade Node first |
FAQ
Q: Is Zod v4 backward-compatible with Zod v3 schemas?
No, Zod v4 has real breaking changes. The most common are: string format methods (.email(), .url(), .uuid()) moved to top-level functions, object strictness helpers (.strict(), .passthrough()) renamed to z.strictObject() / z.looseObject(), and error option keys changed from message to error. The official codemod (npx zod-v3-to-v4) handles the high-volume transforms automatically, but some manual work remains.
Q: Do I need to rewrite my schemas for @zod/mini?
Yes, @zod/mini uses a different API style — function composition instead of method chaining. You cannot simply swap the import; you need to rewrite method chains like z.string().min(3).email() to the function composition equivalent z.string(z.minLength(3), z.email()). Consider @zod/mini only if you’re starting a new project or doing a purposeful frontend bundle optimization pass.
Q: Does Zod v4 work with tRPC?
Yes, as of tRPC v11 (released Q4 2025), Zod v4 is fully supported. If you’re on an older tRPC version, upgrade tRPC alongside Zod.
Q: How long does migration from Zod v3 to v4 take?
Most projects take two to eight hours. Run the codemod first (30 minutes), then address TypeScript errors (tsc --noEmit), then run your test suite. The main time sinks are: custom error message handling that used { message: "..." } syntax (now { error: "..." }), any code that directly instantiates ZodError, and discriminated union schemas with non-literal discriminators.
Q: Is Zod v4 faster for all schema types?
The published benchmarks show 14x faster string parsing, 7x faster array parsing, and 6.5x faster object parsing. These are best-case numbers; real-world gains depend on schema complexity and input characteristics. Schemas with many z.refine() calls or async validators will see smaller gains since those paths weren’t the primary optimization target. For typical REST API request validation with simple object/string/number types, expect gains in the 4–10x range in practice.
