Skip to content

Update zod to 4.3.6 (major)#492

Merged
wereHamster merged 2 commits intomainfrom
syz/update-zod-major
Apr 13, 2026
Merged

Update zod to 4.3.6 (major)#492
wereHamster merged 2 commits intomainfrom
syz/update-zod-major

Conversation

@ghost-of-high-heart
Copy link
Copy Markdown
Contributor

This PR updates zod from version 3.25.76 to 4.3.6. This update crosses a major version boundary.

Release History

The history covers 41 releases. The latest version was published 2 months ago (6 months after the current version).

4.3.6

Published 2 months ago

Commits:

  • 9977fb0868432461de265a773319e80a90ba3e37 Add brand.dev to sponsors
  • f4b7bae3468f6188b8f004e007d722148fc91d77 Update pullfrog.yml (#​5634)
  • 251d7163a0ac7740fee741428d913e3c55702ace Clean up workflow_call
  • edd4132466da0f5065a8e051b599d01fdd1081d8 fix: add missing User-agent to robots.txt and allow all (#​5646)
  • 85db85e9091d0706910d60c7eb2e9c181edd87bd fix: typo in codec.test.ts file (#​5628)
  • cbf77bb12bdfda2e054818e79001f5cb3798ce76 Avoid non null assertion (#​5638)
  • dfbbf1c1ae0c224b8131d80ddf0a264262144086 Avoid re-exported star modules (#​5656)
  • 762e911e5773f949452fd6dd4e360f2362110e8e Generalize numeric key handling
  • ca3c8629c0c2715571f70b44c2433cad3db7fe4e v4.3.6

4.3.5

Published 3 months ago

Commits:

  • 21afffdb42ccab554036312e33fed0ea3cb8f982 [Docs] Update migration guide docs for deprecation of message (#​5595)
  • e36743e513aadb307b29949a80d6eb0dcc8fc278 Improve mini treeshaking
  • 0cdc0b8597999fd9ca99767b912c1e82c1ff2d6c 4.3.5

4.3.4

Published 3 months ago

Commits:

  • 1a8bea3b474eada6f219c163d0d3ad09fadabe72 Add integration tests
  • e01cd02b2f23d7e9078d3813830b146f8a2258b4 Support patternProperties for looserecord (#​5592)
  • 089e5fbb0f58ce96d2c4fb34cd91724c78df4af5 Improve looseRecord docs
  • decef9c418d9a598c3f1bada06891ba5d922c5cd Fix lint
  • 9443aab00d44d5d5f4a7eada65fc0fc851781042 Drop iso time in fromJSONSchema
  • 66bda7491a1b9eab83bdeec0c12f4efc7290bd48 Remove .refine() from ZodMiniType
  • b4ab94ca608cd5b581bfc12b20dd8d95b35b3009 4.3.4

4.3.3

Published 3 months ago

Commits:

  • f3b2151959d215d405f54dff3c7ab3bf1fd887ca v4.3.3

4.3.2

Published 3 months ago

Commits:

  • bf96635d243118de6e4f260077aa137453790bf6 Loosen strictObjectinside intersection (#​5587)
  • f71dc0182ab0f0f9a6be6295b07faca269e10179 Remove Juno (#​5590)
  • 0f41e5a12a43e6913c9dcb501b2b5136ea86500d 4.3.2

4.3.1

Published 3 months ago

Commits:

  • 0fe88407a4149c907929b757dc6618d8afe998fc allow non-overwriting extends with refinements. 4.3.1

4.3.0

Published 3 months ago

This is Zod's biggest release since 4.0. It addresses several of Zod's longest-standing feature requests.

z.fromJSONSchema()

Convert JSON Schema to Zod (#​5534, #​5586)

You can now convert JSON Schema definitions directly into Zod schemas. This function supports JSON Schema "draft-2020-12", "draft-7", "draft-4", and OpenAPI 3.0.

import * as z from "zod";

const schema = z.fromJSONSchema({
  type: "object",
  properties: {
    name: { type: "string", minLength: 1 },
    age: { type: "integer", minimum: 0 },
  },
  required: ["name"],
});

schema.parse({ name: "Alice", age: 30 }); // ✅

The API should be considered experimental. There are no guarantees of 1:1 "round-trip soundness": MySchema > z.toJSONSchema() > z.fromJSONSchema(). There are several features of Zod that don't exist in JSON Schema and vice versa, which makes this virtually impossible.

Features supported:

  • All primitive types (string, number, integer, boolean, null, object, array)
  • String formats (email, uri, uuid, date-time, date, time, ipv4, ipv6, and more)
  • Composition (anyOf, oneOf, allOf)
  • Object constraints (additionalProperties, patternProperties, propertyNames)
  • Array constraints (prefixItems, items, minItems, maxItems)
  • $ref for local references and circular schemas
  • Custom metadata is preserved

z.xor() — exclusive union (#​5534)

A new exclusive union type that requires exactly one option to match. Unlike z.union() which passes if any option matches, z.xor() fails if zero or more than one option matches.

const schema = z.xor([z.string(), z.number()]);

schema.parse("hello"); // ✅
schema.parse(42);      // ✅
schema.parse(true);    // ❌ zero matches

When converted to JSON Schema, z.xor() produces oneOf instead of anyOf.

z.looseRecord() — partial record validation (#​5534)

A new record variant that only validates keys matching the key schema, passing through non-matching keys unchanged. This is used to represent patternProperties in JSON Schema.

const schema = z.looseRecord(z.string().regex(/^S_/), z.string());

schema.parse({ S_name: "John", other: 123 });
// ✅ { S_name: "John", other: 123 }
// only S_name is validated, "other" passes through

.exactOptional() — strict optional properties (#​5589)

A new wrapper that makes a property key-optional (can be omitted) but does not accept undefined as an explicit value.

const schema = z.object({
  a: z.string().optional(),      // accepts `undefined`
  b: z.string().exactOptional(), // does not accept `undefined`
});

schema.parse({});                  // ✅
schema.parse({ a: undefined });    // ✅
schema.parse({ b: undefined });    // ❌

This makes it possible to accurately represent the full spectrum of optionality expressible using exactOptionalPropertyTypes.

.apply()

A utility method for applying arbitrary transformations to a schema, enabling cleaner schema composition. (#​5463)

const setCommonChecks = <T extends z.ZodNumber>(schema: T) => {
  return schema.min(0).max(100);
};

const schema = z.number().apply(setCommonChecks).nullable();

.brand() cardinality

The .brand() method now accepts a second argument to control whether the brand applies to input, output, or both. Closes #​4764, #​4836.

// output only (default)
z.string().brand<"UserId">();           // output is branded (default)
z.string().brand<"UserId", "out">();    // output is branded
z.string().brand<"UserId", "in">();     // input is branded
z.string().brand<"UserId", "inout">();  // both are branded

Type predicates on .refine() (#​5575)

The .refine() method now supports type predicates to narrow the output type:

const schema = z.string().refine((s): s is "a" => s === "a");

type Input = z.input<typeof schema>;   // string
type Output = z.output<typeof schema>; // "a"

ZodMap methods: min, max, nonempty, size (#​5316)

ZodMap now has parity with ZodSet and ZodArray:

const schema = z.map(z.string(), z.number())
  .min(1)
  .max(10)
  .nonempty();

schema.size; // access the size constraint

.with() alias for .check() (359c0db)

A new .with() method has been added as a more readable alias for .check(). Over time, more APIs have been added that don't qualify as "checks". The new method provides a readable alternative that doesn't muddy semantics.

z.string().with(
  z.minLength(5),
  z.toLowerCase()
);

// equivalent to:
z.string().check(
  z.minLength(5),
  z.trim(),
  z.toLowerCase()
);

z.slugify() transform

Transform strings into URL-friendly slugs. Works great with .with():

// Zod
z.string().slugify().parse("Hello World");           // "hello-world"


// Zod Mini
// using .with() for explicit check composition
z.string().with(z.slugify()).parse("Hello World");   // "hello-world"

z.meta() and z.describe() in Zod Mini (947b4eb)

Zod Mini now exports z.meta() and z.describe() as top-level functions for adding metadata to schemas:

import * as z from "zod/mini";

// add description
const schema = z.string().with(
  z.describe("A user's name"),
);

// add arbitrary metadata
const schema2 = z.number().with(
  z.meta({ deprecated: true })
);

More ergonomic intersections https://redirect.github.com/colinhacks/zod/pull/5587

When intersecting schemas that include z.strictObject(), Zod 4 now only rejects keys that are unrecognized by both sides of the intersection. Previously, any unrecognized key from either side would cause an error.

This means keys that are recognized by at least one side of the intersection will now pass validation:

const A = z.strictObject({ a: z.string() });
const B = z.object({ b: z.string() });

const C = z.intersection(A, B);

// Keys recognized by either side now work
C.parse({ a: "foo", b: "bar" }); // ✅ { a: "foo", b: "bar" }

// Extra keys are stripped (follows strip behavior from B)
C.parse({ a: "foo", b: "bar", c: "extra" }); // ✅ { a: "foo", b: "bar" }

When both sides are strict, only keys unrecognized by both sides will error:

const A = z.strictObject({ a: z.string() });
const B = z.strictObject({ b: z.string() });

const C = z.intersection(A, B);

// Keys recognized by either side work
C.parse({ a: "foo", b: "bar" }); // ✅

// Keys unrecognized by BOTH sides error
C.parse({ a: "foo", b: "bar", c: "extra" }); 
// ❌ ZodError: Unrecognized key: "c"

New locales

import * as z from "zod";
import { uz } from "zod/locales";

z.config(uz());




Bug fixes

All of these changes fix soundness issues in Zod. As with any bug fix there's some chance of breakage if you were intentionally or unintentionally relying on this unsound behavior.

⚠️ .pick() and .omit() disallowed on object schemas containing refinements (#​5317)

Using .pick() or .omit() on object schemas with refinements now throws an error. Previously, this would silently drop the refinements, leading to unexpected behavior.

const schema = z.object({
  password: z.string(),
  confirmPassword: z.string(),
}).refine(data => data.password === data.confirmPassword);

schema.pick({ password: true });
// 4.2: refinement silently dropped ⚠️
// 4.3: throws error ❌

Migration: The easiest way to migrate is to create a new schema using the shape of the old one.

const newSchema = z.object(schema.shape).pick({ ... })

⚠️ overwriting properties with.extend() disallowed on object schemas with refinements (#​5317)

Similarly, .extend() will throws on schemas with refinements if you are overwriting existing properties.

const schema = z.object({ 
  a: z.string() 
}).refine(/* ... */);

schema.extend({ a: z.number() }); // 4.3: throws error ❌

Instead you can use .safeExtend(), which statically ensures that you aren't changing the type signature of any pre-existing properties.

const schema = z.object({ 
  a: z.string(),
}).refine(/* ... */);

schema.safeExtend({ 
  a: z.string().min(5).max(10) 
}); // ✅ allows overwrite, preserves refinement

⚠️ Stricter object masking methods (#​5581)

Object masking methods (.pick(), .omit()) now validate that the keys provided actually exist in the schema:

const schema = z.object({ a: z.string() });

// 4.3: throws error for unrecognized keys
schema.pick({ nonexistent: true });
// error: unrecognized key: "nonexistent"




Additional changes

  • Fixed JSON Schema generation for z.iso.time with minute precision (#​5557)
  • Fixed error details for tuples with extraneous elements (#​5555)
  • Fixed includes method params typing to accept string | $ZodCheckIncludesParams (#​5556)
  • Fixed numeric formats error messages to be inclusive (#​5485)
  • Fixed implementAsync inferred type to always be a promise (#​5476)
  • Tightened E.164 regex to require a non-zero leading digit and 7–15 digits total (#​5524)
  • Fixed Dutch (nl) error strings (#​5529)
  • Convert Date instances to numbers in minimum/maximum checks (#​5351)
  • Improved numeric keys handling in z.record() (#​5585)
  • Lazy initialization of ~standard schema property (#​5363)
  • Functions marked as @__NO_SIDE_EFFECTS__ for better tree-shaking (#​5475)
  • Improved metadata tracking across child-parent relationships (#​5578)
  • Improved locale translation approach (#​5584)
  • Dropped id uniqueness enforcement at registry level (#​5574)

4.2.1

Published 3 months ago

Commits:

  • 5b5b129315fbc94a3b0d6244185eaeefcbe438d1 4.2.1

4.2.0

Published 3 months ago

Features

Implement Standard JSON Schema

https://redirect.github.com/standard-schema/standard-schema/pull/134

Implement z.fromJSONSchema()

const jsonSchema = {
  type: "object",
  properties: {
    name: { type: "string" },
    age: { type: "number" }
  },
  required: ["name"]
};

const schema = z.fromJSONSchema(jsonSchema);

Implement z.xor()

const schema = z.xor(
  z.object({ type: "user", name: z.string() }),
  z.object({ type: "admin", role: z.string() })
);
// Exactly one of the schemas must match

Implement z.looseRecord()

const schema = z.looseRecord(z.string(), z.number());
// Allows additional properties beyond those defined

Commits:

  • af49c084f66339110d00e37ff71dc7b3b9f2b7ef Update docs for JSON Schema conversion of z.undefined() (#​5504)
  • 767f320318986e422f524b939f1a7174544fda2e Add .toJSONSchema() method (#​5477)
  • e17dcb63573397063e87d7c7fe10a5a78968181a Add z.fromJSONSchema(), z.looseRecord(), z.xor() (#​5534)

4.1.13

Published 4 months ago

Commits:

  • 5c2602ceb8be8941c64bbe5ac7d92cc174ae6f7e Update AI widget (#​5318)
  • d3da530deb713c853e79405adddf770e156d50ac reflect the specified regex correctly in error (#​5338)
  • 39f8c45b8a29de2330b485862b83cb35849f4238 faster initialization (#​5352)
  • e9e27905cc0f37cb079ea473af8359d5e17a57a1 Clean up comment
  • 8e4739fadbd7de710eb67d34ba7e06a1029a68ab Update inferred z.promise() type
  • 2849df8907b011ab056d67ae8e3d27577ac4ed3e fix(locales): improve Dutch (nl) localization (#​5367)
  • b0d3c9f628b60d358b66acf8f0ef7937fc9e8950 Run tests on windows
  • 6fd61b71b85e4fef4c168a46c3ebcc574f26255f feat unitest (#​5358)
  • a4e4bc80e204577c698cf1369dd63c2b986d35f3 Lock to node 24
  • 8de8bad0fa84194b81efd32474462d7a236a1ee4 Fix windows build
  • b2c186bbae3a74a12acd385c1ced3ed978235cf8 Use Node LTS
  • b73b1f61c798efdf497852872b4c19cd4111c1f3 Consolidate isTransforming logic
  • d85f3ea4da53a1b232017dd4e4a2874eca4d8d76 Fix #​5353
  • 1bac0f37b529eb9a0d833a01200f5a898e8e6220 Fix test.yml
  • 86d4dad5bc27b4b35df533c9170a552ad8c6c3bc Fix partial record
  • 5e6c0fd7471636feffe5763c9b7637879da459fe Fix attw on windows
  • 27fc616b8edb93cc27a4d25b37479d6e418bbccf Extend test timeout
  • 8d336c4d15e1917d78b67b890f7182f26633b56f Remove windows runner
  • 5be72e0ef4dceb1387febb7981079ecdeb5e2817 chore(doc): update metadata.tsx (#​5331)
  • cb0272a0ad9962df95832a78587f54afec685351 docs: add 'cd zod' step to development setup instructions (#​5394)
  • 24e3325dc63010e4f74e23caf91199652e8b12a9 docs: replace 'Refinement' with 'Transform' in transforms section (#​5397)
  • 644a08203ebb00e23484b3f9a986ae783ce26a9a chore: add resource for validating environment variables with Zod (#​5403)
  • 5e1cfcf578a47527044e85455e79c907fd913adc Change doc for email validation method in Zod schema (#​5392)
  • 88cf9441448608d9de24b47b8a4a4ba879fc2433 Fix: Iterate over keys in catchall object using "in" operator. (#​5376)
  • aa437325c5957c0cf57667cd7b8568603ee7ecd3 Emphasise that enum validates against values, for object literal & enums (#​5386)
  • 3a4bd00aaa16276ffeb2708cc083a633bd4dd756 Improve Hebrew localization for Zod error messages (#​5409)
  • c10f9d109874aeca6855383616c086b077d39f89 Fix typos (#​5420)
  • 86f0ef918bb24f4ab9f1ce2afc5cf2d1a4a99473 Documentation Improvements (#​5417)
  • e120a4877f4d8d076abf2db5c5cceab91a046be9 Fix opt tuple
  • f9bbb50c48f9c07ca869d28d6a7086d7290b97a3 Improve tuple
  • 0ba0f348f677688b69ed78473e022f5d225b41fc Optimize docs caching/ISR (#​5433)
  • c3ec66c74b3fbc2616e880a90751c2cad7270bb3 Improve docs caching
  • c8cce4b607a7c0ca99cfb454571a3948ee9e85fb docs: fix typos and links (#​5428)
  • 84ec04708525d6e83e3408d5d3a21edde742bdc5 docs(ecosystem): Add react-f3 (#​5429)
  • 3396515cc6f04f5f346a1e00256ad09998dbaeb3 Docs: Fix typo in safeExtend description (#​5445)
  • 3d93a7d593c19dc1822bc96a7c9d47312c29995e feat: MAC address validation in v4 and mini (#​5440)
  • f2f0d178e1c526bc00ad0385706efad318bd44b0 Fix dual package hazard for globalRegistry (#​5452)
  • 9fc493f86f17a5fc550df78e7e261137885f51ea fix: use oneOf for discriminated unions in JSON Schema (#​5453)
  • 603dbe8dba6253c702ca8cf10b5299910dba3c88 Clean up regex, drop backreferences
  • ab69b9ee813713a111b56a60c2df929eaf5ba426 Update mac addr tests
  • f7910528901c05293bad275fffcb54a82e28fcc9 chore: upgrade vitest to v4 (#​5028)
  • f97e80da9197064937a58167619967bee4ebb638 fix(core): prevent infinite recursion for recursive tuples (#​5089) (#​5094)
  • 002e01ad0fcc17b17683adafc80f2a86e8d355a9 fix(record): handle non-function constructor field in isPlainObject (#​5098)
  • 67165174eb8c7d5c6e76e760830f3109b4fdbd0e docs(contributing): add instructions on building @zod/docs (#​5114)
  • 8b0603dde684f1665bb2329111ed187f73ccf0ac Fix typo in ISO time documentation (#​5277)
  • be85ecc48a83e7f65ac0458d25f832fb4e28c9e7 docs(codecs): correct stringToDate safeDecode methods (#​5302)
  • 50bba5462546401939920a6566a81c0d9c8ef7e1 Add zodgres to ecosystem documentation (#​5308)
  • 377f5d1eb05bfa2631ac1f020d118f5d3ca99c94 Add zod-to-mongo-schema to ecosystem documentation (#​5457)
  • dea32d52a5745eb6ed9aee2ecab4b01f4ccd0313 docs(ecosystem): add fn sphere and zod-compare (#​5326)
  • 02ea4c82ff3e71f39deaa14159f7ce486b337aa0 Add Claude Code GitHub Workflow (#​5460)
  • d44253d6498564ecd24a6248ddca4e9bf4e43058 Add support for number literal and TypeScript's enum keys in z.record (#​5334)
  • f52344e76bed0e69175ca8893c84736cf97b5d11 Fix vitest 4
  • 0f4ce73ad0c5610c3c53857d05ebae619d229aa3 Do not allow unsound pick/omit
  • 162fe298f0ec76d7f7883afbebdd732eb3c60773 Add z.meta and z.describe
  • 3de39eea6f7ed286ae182093d0c91f3a6fdcca06 Implement slugify
  • 5bfc8f269a81d9edc283e7920868161e4129fb23 Fix docs
  • 0e803a29344a2f0ee637940cca96be3e6978b22e Revert "Do not allow unsound pick/omit"
  • a774750d113982da28a2768b0a7c2de1f20c04e8 v4.1.13
  • 2cdd82b663706fdf642d7f030841a5b278f9173c 4.1.13
  • 4063e802d539d04182fc3e66a543ae6d1ba5658e Update check-semver script

4.1.12

Published 6 months ago

Commits:

  • 0b109c37c6b0b10e3901b56bcccb72e29a0b846f docs(ecosystem): add bupkis to the ecosystem section (#​5237)
  • d22ec0d26fab27151b0f1d1f98bffeaf8b011f57 docs(ecosystem): add upfetch (#​5238)
  • c56a4f6fab42c542b191228af61974b2328dc52f docs(ecosystem): add eslint-plugin-zod-x (#​5261)
  • a0abcc02900a4293dd4f30cd81580efcdd5230bb docs(metadata.mdx): fix a mistake in an example output (#​5248)
  • 62bf4e439e287e55c843245b49f8d34b1ad024ee fix(ZodError): prevent flatten() from crashing on 'toString' key (#​5266)
  • 02a584010ac92ac8a351632ae5aea3983a6f17d8 refac(errors): Unify code structure and improve types (#​5278)
  • 4b1922ad714e12dafaa83a40ec03275a39ac980c docs(content/v4/index): fix zod version (#​5289)
  • 3fcb20ff348e49aec70f45e0dca3de8a61450e77 Add frrm to ecosystem (#​5292)
  • fda4c7c2afbd7649261be1e7954f8c4d4de24a07 Make docs work without token
  • af447384379faef28aa857fb53ef1da702c6d408 Fix lint
  • 77c3c9f069a4cf168c0cbc58432803de887a6b1b Export bg.ts
  • 3b946107b6c94b2ac8ff9fb451160c34dc4dd794 v4.1.12

4.1.11

Published 6 months ago

Commits:

  • 2bed4b39760d8e4d678203b5c8fcaf24c182fc9f 4.1.11

4.1.10

Published 6 months ago

Commits:

  • 7ffedd00169d8dc2e7cb7c6d878f29b03e05b3a3 Fix shape caching (#​5263)
  • 82cd717a0e7ee4e1737a783c7be278fa93fd8104 v4.1.10

4.1.9

Published 6 months ago

Commits:

  • a78716d91da7649a61016b81c27f49fd9e79a81e Update zshy (#​5249)
  • 923af801fde9f033cfd7e0e753b421a554fe3be8 Publish zod@4.1.9

4.1.8

Published 7 months ago

Commits:

  • 36c4ee354d0c1f47b7311e49f6dd4b7a11de04f5 Switch back to weakmap
  • a1726d53172ba52ecf90999df73778cf416264fd 4.1.8

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
swiss-maps Ready Ready Preview, Comment Apr 13, 2026 6:19am

Request Review

@wereHamster wereHamster merged commit fad51c4 into main Apr 13, 2026
7 checks passed
@wereHamster wereHamster deleted the syz/update-zod-major branch April 13, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant