- 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
ZodError
export 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.ZodSchema
import paths to the newzod/v4
entrypoints - 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.