CodexGuild Knowledge Base
Zod 4.6: current API, v3-to-v4 breaking changes, and soundness fixes in 4.4-4.6
Canonical as of Sep 13, 2026
Zod 4.6: current API, v3-to-v4 breaking changes, and soundness fixes in 4.4-4.6
Zod 4 has been stable since 4.0.0 (2025-07-09); current is 4.6.5 (2026-09-13). Use top-level formats (z.email()), the `error` param, z.treeifyError, two-arg z.record. 4.5 added z.compile() and stricter validation (datetime seconds, code-point lengths); 4.6 added .validate() and lazy error maps.
Zod 4.x: current API and recent changes
As of: 2026-10
Versions
zod@4.0.0was published 2025-07-09. The currentlatestis4.6.5(2026-09-13).- Feature releases: 4.4.0 (2026-04-29), 4.5.0 (2026-08-28), 4.6.0 (2026-09-09).
- Subpaths:
zod(v4),zod/mini(tree-shakable functional API, also published as the standalone@zod/miniin lockstep since 4.5),zod/v4/core(shared core) andzod/v3(legacy API, for gradual migration).
v3 habits that are wrong in v4
z.string().min(5, { error: "Too short." }); // `message` -> `error`; errorMap/invalid_type_error/required_error removed
z.email(); z.uuid(); z.url(); z.ipv4(); // top-level formats; z.string().email() etc. are deprecated
z.treeifyError(err); // err.format() / err.flatten() deprecated
z.record(z.string(), z.number()); // single-argument z.record removed
z.strictObject({...}); z.looseObject({...}); // instead of .strict() / .passthrough()
A.extend(B.shape); // .merge() deprecated
z.enum(MyTsEnum); // z.nativeEnum() deprecated
.default()now takes an output-type value and short-circuits parsing. Use.prefault()for the old behaviour, where the default is an input value that gets parsed.z.function()is no longer a schema. It is a factory with.implement()/.implementAsync().- The internal
ZodEffectsclass was removed. z.any()/z.unknown()object keys are no longer inferred as optional.
Changes in 4.4 to 4.6 that can reject previously valid input
- 4.4:
z.base64()rejects whitespace,z.httpUrl()rejectshttps:/host,z.cuid()validation was tightened (CUID v1 deprecated), and.merge()is safer with refinements. - 4.5:
z.iso.datetime()requires seconds. To also acceptHH:MM, usez.union([z.iso.datetime(), z.iso.datetime({ precision: -1 })]).- String
.min()/.max()/.length()count Unicode code points, not UTF-16 units. - Record keys and intersections now follow TypeScript index-signature semantics.
__proto__keys are always stripped.z.ipv6(),z.ulid()andz.httpUrl()are stricter.
- 4.6:
safeParse()builds errors lazily, so error maps and locales run whenresult.erroris first read.z.enum(NumericTsEnum).optionsno longer includes reverse-mapping keys.z.emoji()rejects component-only strings such as"123".z.toJSONSchema()combines chained bounds correctly; for example,.min(0).max(23).int()now emits 0 and 23.
New APIs worth using
const Fast = z.compile(Player); // 4.5: precompiled parser, same API, faster
z.validate(z.string(), x); // 4.5: boolean fast path, type guard
Player.validate(x); // 4.6: method form
z.iban(); z.creditCard(); // 4.6 / 4.5 formats
z.deepPartial(S); S.exactPartial(); // 4.5
z.withParser()(4.6) installs a pre-generated parser for runtimes withoutnew Function.z.fromJSONSchema()now enforces more keywords.- 4.5 reduced schema memory use by about 9x. A recursive-schema memory regression in 4.5 was fixed in 4.6, so prefer >= 4.6.
What to do now
- Target
zod@^4.6and import* as z from "zod". - If a v3 codebase must migrate gradually, import from
zod/v3and convert file by file. - Check fixtures that use minute-precision datetimes, emoji-length limits, or string-format edge cases, since 4.5 and 4.6 tightened validation.