- Unified Object Behaviour –
.passthrough()replaces.nonstrict()and better aligns with Zod’s philosophy of explicitness. - Enhanced Metadata APIs –
meta()supersedes several ad-hoc helpers such as.describe(). - Error Handling Revamp – new
ZodErrorexport path and richer error objects. - Union & Intersection Updates – explicit helpers (
z.union,z.intersection) over chained.or()/.and()calls. - Ecosystem Clean-up – deprecated utilities removed, smaller bundle size, faster parse times.
Getting started
Migration Steps
1
Install Zod 4
Install the latest major version of Zod. We recommend using exact versions to avoid surprises:Zod has no peer dependencies, so that’s the only package you need to bump.
2
Run the codemod
Launch the codemod recipe to automatically rewrite common breaking changes:View a list of available CLI commands & options here ->
Can you rollback?Git is your friend—commit before you run the codemod. The Codemod CLI also supports the
--dry-run flag which lets you preview the changes without applying them.What the recipe changes
The migration recipe only targets Zod-specific breaking changes. It will not touch unrelated code patterns likevar declarations or debug console.log statements. Concretely, it performs the following refactors:.nonstrict()→.passthrough()- Chained
.or()/.and()calls →z.union([...])/z.intersection([...]) .describe("…")→.meta({ description: "…" })- Updates
ZodError,z.ZodSchemaimport paths to the newzod/v4entrypoints - Removes helpers removed in v4 (
z.lazyobject, legacy refinements, etc.)
3
Review & test
The codemod handles most changes, but some APIs require manual tweaks. We recommend:
- Type-check the project:
- Run your test suite and fix any remaining failures.
- Search for
TODO(zod-4-migration)comments the codemod leaves behind for ambiguous cases.
4
Before & After examples
Below is a non-exhaustive diff generated by the codemod:
diff
Tested versions
| From | To | Languages |
|---|---|---|
zod@3.22.x | zod@4.0.0 | JavaScript & TypeScript |
FAQ
Does the codemod cover every breaking change?
No. It focuses on the highest-impact, mechanical updates. Review the Zod release notes for edge-cases such as custom.refine() logic or plugin APIs.