Zod 4 introduces a cleaner API, improved TypeScript inference, and several breaking changes aimed at making schema validation both stricter and more ergonomic. Key highlights include:
  1. Unified Object Behaviour.passthrough() replaces .nonstrict() and better aligns with Zod’s philosophy of explicitness.
  2. Enhanced Metadata APIsmeta() supersedes several ad-hoc helpers such as .describe().
  3. Error Handling Revamp – new ZodError export path and richer error objects.
  4. Union & Intersection Updates – explicit helpers (z.union, z.intersection) over chained .or() / .and() calls.
  5. Ecosystem Clean-up – deprecated utilities removed, smaller bundle size, faster parse times.
For a full changelog see the Zod v4 release notes. Codemod provides an automated Zod 3 → 4 upgrade experience. This page walks you through running the codemod and polishing the remaining edge-cases.

Getting started

Migration Steps

1

Install Zod 4

Install the latest major version of Zod. We recommend using exact versions to avoid surprises:
npm install --save-exact zod@^4
# or
yarn add --exact zod@^4
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:
npx codemod@next jssg run zod-3-4
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.
View a list of available CLI commands & options here ->

What the recipe changes

The migration recipe only targets Zod-specific breaking changes. It will not touch unrelated code patterns like var 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 new zod/v4 entrypoints
  • Removes helpers removed in v4 (z.lazyobject, legacy refinements, etc.)
If you see documentation elsewhere mentioning generic tasks such as “modernizing syntax patterns” or “removing debug statements”, those refer to different codemods—not this Zod migration.
3

Review & test

The codemod handles most changes, but some APIs require manual tweaks. We recommend:
  1. Type-check the project:
    pnpm tsc --noEmit
    
  2. Run your test suite and fix any remaining failures.
  3. 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
-import { z, ZodError } from "zod";
+import { z } from "zod/v4";
+import { ZodError } from "zod/v4/core";

-const value = z.literal('yes').or(z.literal('no'));
+const value = z.union([
+  z.literal('yes'),
+  z.literal('no'),
+]);

-const password = z.string().min(8).describe("User's password");
+const password = z.string().min(8).meta({ description: "User's password" });

Tested versions

FromToLanguages
zod@3.22.xzod@4.0.0JavaScript & 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.

My project uses Babel / SWC – is that supported?

Yes. The codemod operates on the output AST and is agnostic of the underlying compiler.