NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #423 most downloaded on npm
TypeScript-first schema declaration and validation library with static type inference
Last release 21 days ago
13 Sep 2026
Ships unpredictably
gaps range from 8 days to 3 months
Nearly every release is documented
notes for 57 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
7 years old
1011 releases · first in 2020
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
There are no breaking changes to the public API of Zod. However some changes can impact ecosystem tools that rely on Zod internals.
Zod 3.23 is now in beta! This is the final 3.x release before Zod 4.0. To try it out:
npm install zod@beta
z.string().date()Zod can now validate ISO 8601 date strings. Thanks @igalklebanov! https://github.com/colinhacks/zod/pull/1766
const schema = z.string().date();
schema.parse("2022-01-01"); // OK
z.string().time()Zod can now validate ISO 8601 time strings. Thanks @igalklebanov! https://github.com/colinhacks/zod/pull/1766
const schema = z.string().time();
schema.parse("12:00:00"); // OK
You can specify sub-second precision using the precision option:
const schema = z.string().time({ precision: 3 });
schema.parse("12:00:00.123"); // OK
schema.parse("12:00:00.123456"); // Error
schema.parse("12:00:00"); // Error
z.string().duration()Zod can now validate ISO 8601 duration strings. Thanks @mastermatt! https://github.com/colinhacks/zod/pull/3265
const schema = z.string().duration();
schema.parse("P3Y6M4DT12H30M5S"); // OK
z.string().datetime()Thanks @bchrobot https://github.com/colinhacks/zod/pull/2522
You can now allow unqualified (timezone-less) datetimes using the local: true flag.
const schema = z.string().datetime({ local: true });
schema.parse("2022-01-01T12:00:00"); // OK
Plus, Zod now validates the day-of-month correctly to ensure no invalid dates (e.g. February 30th) pass validation. Thanks @szamanr! https://github.com/colinhacks/zod/pull/3391
z.string().base64()Zod can now validate base64 strings. Thanks @StefanTerdell! https://github.com/colinhacks/zod/pull/3047
const schema = z.string().base64();
schema.parse("SGVsbG8gV29ybGQ="); // OK
The following can now be used as discriminator keys in z.discriminatedUnion():
ZodOptionalZodNullableZodReadonlyZodBrandedZodCatchconst schema = z.discriminatedUnion("type", [
z.object({ type: z.literal("A").optional(), value: z.number() }),
z.object({ type: z.literal("B").nullable(), value: z.string() }),
z.object({ type: z.literal("C").readonly(), value: z.boolean() }),
z.object({ type: z.literal("D").readonly(), value: z.boolean() }),
z.object({ type: z.literal("E").catch("E"), value: z.unknown() }),
]);
There are no breaking changes to the public API of Zod. However some changes can impact ecosystem tools that rely on Zod internals.
ZodFirstPartySchemaTypesThree new types have been added to the ZodFirstPartySchemaTypes union. This may impact some codegen libraries. https://github.com/colinhacks/zod/pull/3247
+ | ZodPipeline<any, any>
+ | ZodReadonly<any>
+ | ZodSymbol;
ZodTypeThe third argument of the ZodType base class now defaults to unknown. This makes it easier to define recursive schemas and write generic functions that accept Zod schemas.
- class ZodType<Output = any, Def extends ZodTypeDef = ZodTypeDef, Input = Output> {}
+ class ZodType<Output = unknown, Def extends ZodTypeDef = ZodTypeDef, Input = unknown> {}
.pick() and .omit()This version fixes a bug where unknown keys were accidentally accepted in .pick() and omit(). This has been fixed, which could cause compiler errors in some user code. https://github.com/colinhacks/zod/pull/3255
z.object({
name: z.string()
}).pick({
notAKey: true // no longer allowed
})
ZodFirstPartySchemaTypes by @MatthijsMud in https://github.com/colinhacks/zod/pull/3247input of .required() readonly by @KATT in https://github.com/colinhacks/zod/pull/3301addQuestionMarks, fix #2184 by @colinhacks in https://github.com/colinhacks/zod/pull/3352src for bun test by @rotu in https://github.com/colinhacks/zod/pull/3038zod-dev utility to eco-system section by @schalkventer in https://github.com/colinhacks/zod/pull/3113orval to "X to Zod" ecosystems by @soartec-lab in https://github.com/colinhacks/zod/pull/3397Full Changelog: https://github.com/colinhacks/zod/compare/v3.22.4...v3.23.0-beta
Nothing published for this version
699ccae13b875d4fcadac268fd789c93b6ce8aef Export jsdoc with @deprecated when building
zod-sandbox to README ecosystem links (#2707)@deprecated when building (#2717)2ba00fe2377f4d53947a84b8cdb314a63bbd6dd4 [2609] fix ReDoS vulnerability in email regex
13d9e6bda286cbd4c1b177171273695d8309e5de Fix lint
Fix handing of this in ZodFunction schemas. The parse logic for function schemas now requires the Reflect API.
Fix handing of this in ZodFunction schemas. The parse logic for function schemas now requires the Reflect API.
const methodObject = z.object({
property: z.number(),
method: z.function().args(z.string()).returns(z.number()),
});
const methodInstance = {
property: 3,
method: function (s: string) {
return s.length + this.property;
},
};
const parsed = methodObject.parse(methodInstance);
parsed.method("length=8"); // => 11 (8 length + 3 property)
00bdd0a7ffdf495af14e67ae1396c85a282c38dd fix proto pollution vulnerability
ZodReadonlyThis release introduces ZodReadonly and the .readonly() method on ZodType.
Calling .readonly() on any schema returns a ZodReadonly instance that wraps the original schema. The new schema parses all inputs using the original schema, then calls Object.freeze() on the result. The inferred type is also marked as readonly.
const schema = z.object({ name: string }).readonly();
type schema = z.infer<typeof schema>;
// Readonly<{name: string}>
const result = schema.parse({ name: "fido" });
result.name = "simba"; // error
The inferred type uses TypeScript's built-in readonly types when relevant.
z.array(z.string()).readonly();
// readonly string[]
z.tuple([z.string(), z.number()]).readonly();
// readonly [string, number]
z.map(z.string(), z.date()).readonly();
// ReadonlyMap<string, Date>
z.set(z.string()).readonly();
// ReadonlySet<Promise<string>>
zocker to Ecosystem section (#2416)ZodString.email (#2274)zod-openapi to ecosystem (#2434)exports.types field to first spot @ package.json. (#2443)zodock to mocking ecosystem (#2394)*.md pattern to prettier (#2476)runtypes (#2536)Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
22f3cc6ed52a28c984a0319a1a03e1af244cee02 3.21.4
14c08d87129c3b652f03d2e724979c383c55e0b4 added more .pipe examples
.pipe examplesb276d71eaefef6cb87c81e8429bd160e4b68c168 Improve typings in generics
4f8946182ee07eb7b5d40efa908b1715414e8929 Prettier
Support for ULID validation
z.string().ulid();
toLowerCase and toUpperCase back in for v3.21.0z.custom example again :D.includes(value, options?) @ ZodString. (#1887)edc3a67e77d33979b3ee9e071557b4ca53298c55 Deprecate deepPartial
z.string().emoji()Thanks @joseph-lozano for https://github.com/colinhacks/zod/pull/2045! To validate that all characters in a string are emoji:
z.string().emoji()
...if that's something you want to do for some reason.
z.string().cuid2()Thanks @joulev for https://github.com/colinhacks/zod/pull/1813! To validate CUIDv2:
z.string().cuid2()
z.string().ip()Thanks @fvckDesa for https://github.com/colinhacks/zod/pull/2066. To validate that a string is a valid IP address:
const v4IP = "122.122.122.122";
const v6IP = "6097:adfa:6f0b:220d:db08:5021:6191:7990";
// matches both IPv4 and IPv6 by default
const ipSchema = z.string().ip();
ipSchema.parse(v4IP) // pass
ipSchema.parse(v6IP) // pass
To specify a particular version:
const ipv4Schema = z.string().ip({ version: "v4" });
const ipv6Schema = z.string().ip({ version: "v6" });
z.bigint().{gt|gte|lt|lte}()Thanks @igalklebanov for #1711! ZodBigInt gets the same set of methods found on ZodNumber:
z.bigint().gt(BigInt(5));
z.bigint().gte(BigInt(5));
z.bigint().lt(BigInt(5));
z.bigint().lte(BigInt(5));
z.bigint().positive();
z.bigint().negative();
z.bigint().nonnegative();
z.bigint().nonpositive();
z.bigint().multipleOf(BigInt(5));
z.enum(...).extract() and z.enum(...).exclude()Thanks @santosmarco-caribou for https://github.com/colinhacks/zod/pull/1652! To add or remove elements from a ZodEnum:
const FoodEnum = z.enum(["Pasta", "Pizza", "Tacos", "Burgers", "Salad"]);
const ItalianEnum = FoodEnum.extract(["Pasta", "Pizza"]); // ZodEnum<["Pasta", "Pizza"]>
const UnhealthyEnum = FoodEnum.exclude(["Salad"]); // ZodEnum<["Pasta", "Pizza", "Tacos", "Burgers"]>
This API is inspired by the Exclude and Extract TypeScript built-ins.
.catch()Thanks @0xWryth for https://github.com/colinhacks/zod/pull/2087! The .catch() method now accepts a function that receives the caught error:
const numberWithErrorCatch = z.number().catch((ctx) => {
ctx.error; // ZodError
return 42;
});
Zod 3.20.2 introduced an accidental type recursion that caused long compilation times for some users. These kinds of bugs are very hard to diagnose. Big shoutout to @gydroperit for some heroic efforts here: https://github.com/colinhacks/zod/pull/2107 Zod 3.21 resolves these issues:
.catch error (#2087)ZodBigInt. (#1711)toLowerCase and toUpperCaseZodNumber.safe() & ZodNumber.isSafe. (#1753)e6939195fbb5191402ba3d6f5b7aade463de6e51 3.20.6
e71c7be15e393e0932aa3c939d061f8444f6ae29 Fix extract/exclude type error
b8d731f779679e6f47cde18b2c422b0d4f44b01d Set input type of ZodCatch to unknown
Nothing published for this version
Add string cuid2() validation by @joulev in https://github.com/colinhacks/zod/pull/1813
ZodNumber.isFinite, make ZodNumber.isInt true if .multipleOf(int). by @igalklebanov in https://github.com/colinhacks/zod/pull/1714extract/exclude methods to ZodEnum by @santosmarco-caribou in https://github.com/colinhacks/zod/pull/1652z.coerce. by @igalklebanov in https://github.com/colinhacks/zod/pull/1680isAsync type guard by @aaronccasanova in https://github.com/colinhacks/zod/pull/1719ZodCatch by @santosmarco-caribou in https://github.com/colinhacks/zod/pull/1733deno/lib/README.md to match zod/README.md by @JacobWeisenburger in https://github.com/colinhacks/zod/pull/1791.describe() by @rattrayalex in https://github.com/colinhacks/zod/pull/1819.pick, .omit, .partial & .required. by @igalklebanov in https://github.com/colinhacks/zod/pull/1875ZodObject's .omit(mask),.pick(mask),.required(mask) & .partial(mask) at compile time. by @igalklebanov in https://github.com/colinhacks/zod/pull/1564Full Changelog: https://github.com/colinhacks/zod/compare/v3.20.2...v3.20.3
d7d49e77ccd758ee874f7866862840f88f75cbb6 Clarify boolean coercion
1298d26115e09cf097cb272cfc3184484eb64fd1 Update readme
There are no breaking API changes, however TypeScript versions 4.4 and earlier are no longer officially supported.
There are no breaking API changes, however TypeScript versions 4.4 and earlier are no longer officially supported.
The most feature-packed release since Zod 3.0!
.pipe()A new schema method .pipe() is now available on all schemas. which can be used to chain multiple schemas into a "validation pipeline". Typically this will be used in conjunction with .transform().
z.string()
.transform(val => val.length)
.pipe(z.number().min(5))
The .pipe() method returns a ZodPipeline instance.
z.coerceZod now provides a more convenient way to coerce primitive values.
const schema = z.coerce.string();
schema.parse("tuna"); // => "tuna"
schema.parse(12); // => "12"
schema.parse(true); // => "true"
During the parsing step, the input is passed through the String() function, which is a JavaScript built-in for coercing data into strings. Note that the returned schema is a ZodString instance so you can use all string methods.
z.coerce.string().email().min(5);
All primitive types support coercion.
z.coerce.string(); // String(input)
z.coerce.number(); // Number(input)
z.coerce.boolean(); // Boolean(input)
z.coerce.bigint(); // BigInt(input)
z.coerce.date(); // new Date(input)
.catch()A new schema method .catch() is now available on all schemas. It can be used to provide a "catchall" value that will be returned in the event of a parsing error.
const schema = z.string().catch("fallback");
schema.parse("kate"); // => "kate"
schema.parse(4); // => "fallback"
The .catch() method returns a ZodCatch instance.
z.symbol()A long-missing hole in Zod's type system is finally filled! Thanks @santosmarco-caribou.
const schema = z.symbol();
schema.parse(Symbol('asdf'));
Relatedly, you can also pass symbols into z.literal().
const TUNA = Symbol("tuna");
const schema = z.literal(TUNA);
schema.parse(TUNA); // Symbol(tuna)
schema.parse(Symbol("nottuna")); // Error
z.string().datetime()A new method has been added to ZodString to validate ISO datetime strings. Thanks @samchungy!
z.string().datetime();
This method defaults to only allowing UTC datetimes (the ones that end in "Z"). No timezone offsets are allowed; arbitrary sub-second precision is supported.
const dt = z.string().datetime();
dt.parse("2020-01-01T00:00:00Z"); // 🟢
dt.parse("2020-01-01T00:00:00.123Z"); // 🟢
dt.parse("2020-01-01T00:00:00.123456Z"); // 🟢 (arbitrary precision)
dt.parse("2020-01-01T00:00:00+02:00"); // 🔴 (no offsets allowed)
Offsets can be supported with the offset parameter.
const a = z.string().datetime({ offset: true });
a.parse("2020-01-01T00:00:00+02:00"); // 🟢 offset allowed
You can additionally constrain the allowable precision. This specifies the number of digits that should follow the decimal point.
const b = z.string().datetime({ precision: 3 })
b.parse("2020-01-01T00:00:00.123Z"); // 🟢 precision of 3 decimal points
b.parse("2020-01-01T00:00:00Z"); // 🔴 invalid precision
z.number().finite()Restrict a number schema to finite values. Thanks @igalklebanov.
const schema = z.number().finite();
schema.parse(5); 🟢
schema.parse(Infinity); 🔴
schema.parse(-Infinity); 🔴
mask parameter to .required method by @SrBrahma in https://github.com/colinhacks/zod/pull/1315fatal to ZodIssue. by @igalklebanov in https://github.com/colinhacks/zod/pull/1555.finite() @ ZodNumber. by @igalklebanov in https://github.com/colinhacks/zod/pull/1546.required() doesn't remove optional flag from the result of .nullish(). by @igalklebanov in https://github.com/colinhacks/zod/pull/1542datetime() string formats by @samchungy in https://github.com/colinhacks/zod/pull/1494path parameter into account within .parseAsync() by @RobinTail in https://github.com/colinhacks/zod/pull/1513ZodSymbol by @santosmarco-caribou in https://github.com/colinhacks/zod/pull/1448Full Changelog: https://github.com/colinhacks/zod/compare/v3.19.1...v3.20.0
Nothing published for this version
d04b303f9b616080c56dae25199bdd5cf2803f20 Update stale
9066b9e6736b7f7669d867b405fdd3b4db16ff91 docs: fix links to anatine plugins in README
Nothing published for this version
b3e623eafa5f4011675afce33e21d244dd25e775 docs: add zodios to zod ecosystem
d9c3637e1338583768922fb8535c163fa046c9c2 fix typo after ac2fb4a
1d16205a84c90ee2f0903e171e40b53c5da906cf feat(enum): return enum from object keys
undefined fields. (#1175)dcc1483c063ccc0ab9061fe7bfcf296be81d8410 Add deno release workflow
a59c38452ed970e129ee9057c4e6d003d4d017bb Fix inferred function types
f73eabca9008a9ab87c8a30c5d506d8e092768d2 Add zod-xlsx to the ecosystem section in README
zod-xlsx to the ecosystem section in README (#1203)63f48194a6524aea59d711c02d6606a5d982d1fc Allow empty commits
Add seasoned to sponsors by @colinhacks in https://github.com/colinhacks/zod/pull/1167
Full Changelog: https://github.com/colinhacks/zod/compare/v3.17.3...v3.17.4
847cedf10d633cd420fbc29243894b1f846cc54f Remove type only imports
44916fe7dee9413216ee0b24001cfbf835cda584 Remove circular dependency
Your coding agent can read these notes before it upgrades. Set up the MCP server →