npm / zod
zod
What changed in zod 4, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-17.
zod 4216 changes
Breaking changes 41
The standalone z.properties() schema is removed; the .properties() method form remains available.
Now enforces minProperties, maxProperties, uniqueItems, contains, minContains, and maxContains instead of ignoring them.
Error maps now run when result.error is first read, so configuration changes between parsing and reading affect the message.
Rejects component-only strings and now requires at least one pictograph, regional indicator, or keycap.
Embedding z.email no longer applies the email segment's no-consecutive-dots rule to the rest of the template string.
Folds chained checks as a conjunction so tighter bounds are preserved and check order no longer changes emitted JSON Schema.
Empty enums and literals now match nothing.
Imported tuples are open-ended by default.
String exact-length validation now counts Unicode code points instead of UTF-16 code units.
String maximum-length validation now counts Unicode code points instead of UTF-16 code units.
String minimum-length validation now counts Unicode code points instead of UTF-16 code units.
Parsed objects consistently strip __proto__ keys, improving protection against prototype pollution.
Object and record parsers strip __proto__ keys and protect formatters and JSON Schema converters from prototype pollution paths.
Record key schemas now govern only matching keys, and pattern-keyed record intersections no longer reject unrelated object keys.
Strict object parsing reports an own __proto__ key instead of treating it as inherited.
Measures string length in Unicode code points.
Zod Mini requires registering a memoizer before defining schemas to support cyclical inputs.
Requires seconds when a datetime includes Z or an offset.
Enforces RFC 1035 host length limits, matching z.hostname().
Validates IPv6 strings directly against the address alphabet, rejecting values previously accepted through URL parsing.
RFC 3339 datetime validation now requires seconds unless local mode is enabled.
Rejects ULIDs whose first character exceeds 7 because the encoded timestamp would overflow 48 bits.
Base64 validation rejects whitespace to prevent an atob bypass.
The ecosystem ESLint plugin is now named eslint-plugin-zod instead of eslint-plugin-zod-x.
Non-JSON-like inputs such as cyclic objects and BigInt are now rejected or normalized more consistently.
The .merge() method now throws when the receiver has refinements, avoiding ambiguous refinement behavior.
Merging a schema with receiver refinements now throws, while refinements from the second schema are preserved.
Object catchall paths now skip __proto__ keys to harden against prototype pollution.
Object catchall parsing skips the __proto__ key.
Tuple defaults now materialize in parsed output, while absent optional tails remain absent and explicit undefined values are preserved.
Base64 validation now rejects whitespace instead of accepting inputs after atob-style whitespace stripping.
CUID validation has been tightened, changing which inputs are accepted.
Malformed HTTP(S) URLs missing a slash after the protocol are now rejected instead of being accepted after URL normalization.
Object properties using z.undefined() are now required to be present; use .optional() when the key may be absent.
ISO time handling was dropped from fromJSONSchema.
ZodMiniType no longer provides the refine method.
Tightens the E.164 regex to require a non-zero leading digit and 7–15 total digits.
Throws when overwriting existing properties on object schemas with refinements.
Throws when called on object schemas containing refinements instead of silently dropping those refinements.
Throws when called on object schemas containing refinements instead of silently dropping those refinements.
Intersections reject keys only when unrecognized by both sides, allowing keys recognized by either side to pass validation.
Security 2
Uses linear runtime character-set validation with code-enforced length and padding, preventing regex stack overflow on huge inputs.
Reserved-key handling is hardened across Zod 4 schemas.
Deprecations 3
The cuid regex is tightened and CUID v1 is deprecated.
CUID v1 is now deprecated.
The message API is deprecated; developers should consult the migration guide for the replacement.
New APIs and options 65
Adds z.currencyCode() using a vendored ISO 4217 list refreshed weekly by CI.
Adds the Tajik locale for localized Zod messages.
Adds asynchronous boolean validation for schemas with async refinements.
Adds IBAN string validation in electronic format with an ISO 7064 MOD 97-10 checksum.
Adds a properties method for validating properties on instances without replacing the instance.
Adds in-place validation of selected object properties while preserving the input instance and prototype.
Allows extra arguments to be passed to apply().
Bun can preload zod/compile through the preload configuration.
Adds partial schemas that allow omitted keys but reject explicitly provided undefined values.
Supports format: "hostname" when converting JSON Schema.
Adds Hindi, Kannada, Slovak, Bengali, Turkmen, Norwegian Nynorsk, Central Kurdish, Brazilian Portuguese, Greek, and Croatian locale support.
Node.js can preload zod/compile before application modules define schemas.
Nub can preload zod/compile through the preload configuration.
Allows tuple items to become optional with .partial().
Accepts a function for unrepresentable values and runs override before the unrepresentable error.
Adds boolean validation without constructing a result or ZodError, with type-guard narrowing and short-circuiting.
Pre-compiles any Zod schema for substantially faster parsing while preserving normal schema behavior and error reporting.
Adds ahead-of-time schema compilation.
Adds string validation for 12–19 digit credit-card values with optional separators and a valid Luhn checksum.
Adds credit-card string validation.
Restores deep partial schema construction as a top-level functional API.
Adds deep partial schemas and runtime z.input and z.output helpers.
Adds extraction of a discriminated-union member by discriminator value.
Adds a helper for retrieving a discriminated-union option.
Results from .implement() expose the underlying function schema.
Adds projection of a schema onto its input side for independently validating codec inputs.
Adds synchronous and asynchronous boolean validation helpers.
Accepts a custom length for generated or validated NanoIDs.
Object shapes can declare symbol keys, which are tracked by TypeScript and validated as required keys.
Adds projection of a schema onto its output side for independently validating codec outputs.
Adds a multi-property counterpart to z.property() for checking several properties together.
Exposes stringbool truthy, falsy, and case settings through _zod.bag.
Adds a utility for defining a Zod schema that agrees exactly with a static TypeScript type.
Adds the z.toZod helper.
Adds asynchronous boolean validation for schemas with async refinements.
Importing zod/compile automatically compiles schemas when they are first used to parse data.
Adds .exactPartial() to ZodObject.
Croatian locale support was added.
Greek locale support was added.
The JSONType export was added.
A Romanian locale is added for Zod error messages.
Romanian locale support was added.
The when option was added to conditionally run .superRefine() checks.
Transform callbacks can now report validation issues through ctx.addIssue().
Uzbek map support was added to locale support.
Codec inversion was added, allowing a codec with reversed input and output directions.
looseRecord now supports patternProperties.
Adds a utility method for applying arbitrary transformations to a schema.
Adds the Armenian locale for localized Zod error messages.
Accepts a second argument controlling whether branding applies to input, output, or both.
Adds a wrapper that permits omitted properties but rejects explicit undefined values.
Adds an extension method that preserves refinements while statically preventing incompatible property overwrites.
Adds the Uzbek locale for localized Zod error messages.
Adds a more readable alias for check to support explicit schema composition.
Converts JSON Schema definitions directly into Zod schemas, supporting several JSON Schema drafts and OpenAPI 3.0.
Adds record validation that validates matching keys while passing through non-matching keys unchanged.
Adds z.fromJSONSchema() to create a Zod schema from a JSON Schema definition.
Adds z.looseRecord() to allow additional properties beyond those defined.
Zod implements Standard JSON Schema interoperability.
Adds a .toJSONSchema() method for converting Zod schemas to JSON Schema.
Adds an exclusive union that requires exactly one option to match and emits oneOf in JSON Schema.
Adds z.describe for describing schemas.
MAC address validation was added to Zod 4 and Zod Mini.
Adds z.meta for attaching metadata to schemas.
Adds a transform that converts strings into URL-friendly slugs.
Performance 12
Size bounds are checked before parsing elements, preventing unnecessary element parsing.
Invalid URL rejection is about 50x faster with fewer allocations during validation.
The CommonJS build uses plain properties and frozen exports, making namespace calls such as z.validate faster under require.
Removes lookaheads from the email pattern while preserving validation behavior, making valid-address validation roughly twice as fast.
The emoji regex no longer uses exponential backtracking.
Failure-path safeParse no longer captures an error stack trace, making invalid parses substantially faster.
Schema instances retain substantially less heap memory through lazy method memoization.
Three dead declarations can now be removed by esbuild tree shaking.
Avoids exponential regex backtracking when emoji validation fails.
ZodError construction is deferred, reducing unnecessary error-construction work.
Classic builder methods are lazily bound through a shared prototype, reducing per-schema method allocation overhead.
Top-level factory calls are marked pure so bundlers can eliminate unused code more effectively.
Behavior and default changes 28
Record input and output types are declared as members rather than base type arguments.
The .properties() shape is keyed off the instance type.
Zod Classic metadata members are prototype getters that materialize as own properties only after first read.
Recursive schemas now support cyclical input data and preserve cyclic references in parsed results.
Emits a root $ref when the root schema has an id.
Compacts simple anyOf unions into a JSON Schema type array.
Unrecognized-key issues no longer abort their schema, allowing strict-object extra-key and invalid-value issues to be reported together.
Dynamic .catch() is allowed when unrepresentable is set to any.
Falls back instead of throwing when compilation cannot be used.
Supports declared symbol keys in object schemas.
Parses input containing reference cycles.
Generates a JSON Schema pattern allowing at least N leading characters for includes with a position.
Discriminated union option typing is tightened.
Optionality is deferred to the inner schema.
Invalid discriminated union errors now include discriminator options and improved messages.
Global configuration is now shared through globalThis across mixed CommonJS and ESM module instances.
globalConfig is shared across module systems through globalThis.
Jitless mode now avoids eval probing when enabled before first access.
Object and tuple optionality handling is aligned, including optionality propagation behavior.
Object constructors and shape operations apply writable types for consistent shape display and inference.
Key schema transforms are now applied when parsing records.
Generated stub package manifests now declare sideEffects: false, improving bundler tree-shaking.
Record key refinement failures now surface as structured invalid_key issues.
Record schemas now apply transforms to record keys before producing parsed output.
Numeric key handling was generalized, potentially affecting schemas or APIs that process numeric keys.
strictObject is less restrictive when used inside an intersection.
Removes registry-level enforcement that metadata IDs must be unique.
z.record now supports number literal keys and TypeScript enum keys.
Fixes and other changes 65
Preserves undefined prefault outputs and object keys, preventing those values or keys from being lost.
Unique tags are preserved when discriminators have defaults.
Recursive object index inference is deferred.
Cycle walking no longer fires a default factory unexpectedly.
Record numeric keys are emitted as strings in JSON Schema output.
Prototype method getters now answer a bare call, allowing vi.spyOn to work.
Stops resurrecting issues that an optional schema already resolved.
Builds catch context from the input that failed.
The cidrv6 JSON Schema pattern now matches runtime validation.
Constrains emitted JSON Schema tuple length.
The default English locale is preserved in tree-shaken bundles.
Error-tree walkers use own-property semantics consistently.
formatError correctly handles inherited-name path elements.
Respects additionalProperties:false together with patternProperties.
propertyNames now composes with the other object keywords.
Correctly escapes and unescapes reserved JSON Pointer characters in JSON Schema references.
JSON Schema conversion keeps __proto__ keys as own properties.
Corrects date/time format keywords in both JSON Schema directions.
The documented keyof() ZodEnum type uses the Zod 4 form.
Allows bundlers to tree-shake locales out of the default import.
Accepts exact decimal multiples that were previously rejected.
Declared __proto__ keys are written as own properties.
Record input keys become optional when the value schema can supply them.
No longer throws when bigint multipleOf is configured as 0n.
treeifyError correctly handles inherited-name path elements.
Record keys are re-checked after the key schema runs, preventing transformed keys from bypassing validation.
Catch handling for absent object keys was restored.
Preprocess handling for absent object keys was restored.
Opt-in and fallback behavior was generalized to transform.
Tuple holes are rejected before required defaults are applied, correcting validation behavior.
Map and Set defaults are cloned during parsing, preventing shared state across parses.
Encoding now works when the discriminator uses a codec.
French issue origin translations were added or updated.
Schema generation applies metadata more consistently across several JSON Schema constructs.
The Georgian translation for string validation was corrected.
Italian validation messages were updated.
The allowsEval probe now honors the jitless configuration.
Length validation logic is corrected so schemas validate lengths as intended.
Map defaults are now cloned instead of shared across parses.
Floating-point multipleOf validation is now more accurate for decimal and exponent edge cases.
Parse functions preserve context immutability.
Falsy prefault values are emitted correctly in generated JSON Schema.
Set defaults are now cloned instead of shared across parses.
Floating-point step validation is now more accurate for decimal and exponent edge cases.
Empty unions are constructed instead of causing a crash.
Nested union paths are now preserved correctly in formatted errors.
Non-enumerable properties are now skipped more consistently during record validation.
The v3-style single-argument z.record(valueType) form works again.
Redundant id fields are removed from $defs entries to preserve correct reference resolution in older JSON Schema dialects.
Nested union paths are now preserved correctly in treeified errors.
Empty unions now construct successfully and fail at parse time instead of crashing during construction.
Empty xor schemas now construct successfully and fail at parse time instead of crashing during construction.
extend now allows non-overwriting extensions on schemas with refinements.
Fixes inferred types so implementAsync always returns a promise.
Updates parameter typing to accept string or $ZodCheckIncludesParams.
Converts Date instances to numbers for maximum checks.
Converts Date instances to numbers for minimum checks.
Fixes JSON Schema generation for time values with minute precision.
Improves handling of numeric keys in record schemas.
The dual package hazard affecting globalRegistry was fixed for projects using multiple package entry points.
Partial record handling was fixed for schemas using partial record behavior.
Recursive tuples no longer trigger infinite recursion during processing.
Regexes are reflected correctly in validation errors, making reported patterns accurate to developers.
The inferred type for z.promise() was corrected, improving TypeScript accuracy for promise schemas.
Discriminated unions now use oneOf in generated JSON Schema.