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.
4459e75b8e04bcddb06c2a4a3953a4599dcfc4bc feat: trim method for ZodString
Full Changelog: https://github.com/colinhacks/zod/compare/v3.16.1...v3.17.0
347332c30b801c608ea29c89f61f0247a953bb83 Improve JSDoc deprecation warning for nonempty
cb2b86c3d7c3f1c6fd3c503543f3e3668df7bad5 Update README.md
nestjs-graphql-zod to ecosystem links (#1126)f814ef21ec3e701ea1cdaefdc69dfb59e8ad62d1 Improve docs
d54ba359eda7e74f7373e612153e8e408904b14a feat: allow ctx.addIssue from transform
21aab2a4b04428d7afe6255e78271db0617d6e61 fix(readme): Use Correct Test Link
Literal from the schema in JSON type example (#1083)823dda93193ab23f07b7e4625e54b1e8528cc530 Add invalid_literal issue
66f044b5c3fb2a21df6c8a854fb212852ce0aad9 Improve precommit hooks
76d2fe0b321e8211d470b7d340780218e6fab941 Faster optional & nullable values
Reduce memory churn, avoid generating ctx when not necessary, much faster valid primitives by @tmcw in https://github.com/colinhacks/zod/pull/1025
Full Changelog: https://github.com/colinhacks/zod/compare/v3.14.0...v3.14.1
Add realworld benchmark by @tmcw in https://github.com/colinhacks/zod/pull/1024
Full Changelog: https://github.com/colinhacks/zod/compare/v3.13.4...v3.14.0
Implement .enum on ZodNativeEnum[]
Full Changelog: https://github.com/colinhacks/zod/compare/v3.13.2...v3.13.4
Nothing published for this version
Removing source maps and uglification of ES modules
types field to exports in package.json by @shroudedcode in https://github.com/colinhacks/zod/pull/906Full Changelog: https://github.com/colinhacks/zod/compare/v3.12.0...v3.13.2
Nothing published for this version
Nothing published for this version
Fix documentation for ZodArray .element (issue #744) by @maxmvsk in https://github.com/colinhacks/zod/pull/745
description to ProcessedCreateParams by @equt in https://github.com/colinhacks/zod/pull/767processCreateParams in ZodNumber by @equt in https://github.com/colinhacks/zod/pull/766Support type guards as refinements #727 Fix #732
Support type guards as refinements #727 Fix #732
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
New parsing engine. Zod now surfaces more errors.
New parsing engine. Zod now surfaces more errors.
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
`ts const name = z.string({ invalid_type_error: "Name must be string", required_error: "Name is required", }); `
const name = z.string({
invalid_type_error: "Name must be string",
required_error: "Name is required",
});
Under the hood, this creates a custom error map that's bound to the schema. You can also pass a custom error map explicitly.
const name = z.string({ errorMap: myErrorMap });
const myTuple = z.tuple([z.string(), z.number()]).rest(z.boolean());
type t1 = z.output<typeof myTuple>; // [string, number, ...boolean[]]
.partialYou can specify certain fields to make optional with the ZodObject.partial method.
const user = z.object({
name: z.string(),
age: z.number(),
});
const optionalNameUser = user.partial({ name: true });
// { name?: string; age: number; }
Previously, z.record only accepted a single schema:
z.record(z.boolean()); // Record<string, boolean>;
Now z.record has been overloaded to support two schemas. The first validates the keys of the record, and the second validates the values.
const schema = z.record(z.number(), z.boolean());
type schema = z.infer<typeof schema>; // Record<number, boolean>
const schema = z.record(z.enum(["Tuna", "Trout"]), z.boolean());
type schema = z.infer<typeof schema>; // Record<"Tuna" | "Trout", boolean>
Certain issue types "short circuit" the rest of the validation logic. If you pass a number into a ZodString schema, Zod throws an error immediately, without passing the input through any downstream refinements or transforms. This is intentional; those refinements/transforms are likely to throw unexpected errors since they assume a number input.
However other kinds of errors shouldn't "short circuit" like this. For instance z.string().min(10).email(). If we try to parse "asdf" with this schema, we should get two errors: "Invalid email" and "Input should contain at least 10 characters". If we short circuit after the "min" error, then Zod fails to surface the full set of validation issues.
Zod now considers certain classes of validation errors "continuable", in that they don't short circuit validation logic. This makes Zod more usable in form validation settings like this:
const user = z
.object({
password: z.string().min(6),
confirm: z.string(),
})
.refine((data) => data.password === data.confirm, "Passwords don't match");
const result = user.safeParse({ password: "asdf", confirm: "qwer" });
This will return an error with two issues. Previously the parsing would have short-circuited after the inner password was invalid.
/*
ZodError: [
{
"code": "too_small",
"minimum": 6,
"type": "string",
"inclusive": true,
"message": "Should be at least 6 characters",
"path": [ "password" ]
},
{
"code": "custom",
"message": "Passwords don't match",
"path": [ "confirm" ]
}
]
*/
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
This lets you transform input data before it is parsed by your schema. This is useful for several use cases, notably *type coercion*. Usage:
Release: zod@3.8.0
What's new:
z.preprocessThis lets you transform input data before it is parsed by your schema. This is useful for several use cases, notably type coercion. Usage:
const coercedString = z.preprocess(
val => String(val),
z.string()
)
mySchema.parse(12); // => "12"
mySchema.parse(true); // => "true"
Courtesy of @alii
const cuid = z.string().cuid()
cuid.parse("ckopqwooh000001la8mbi2im9");
.deepPartial()The .deepPartial() method on object schemas now recursively traverses through ZodArray, ZodTuple, ZodOptional, and ZodNullable elements. Previously, this method only worked in hierarchies of simple object schemas.
const mySchema = z.object({
name: z.string(),
array: z.array(z.object({ asdf: z.string() })),
tuple: z.tuple([
z.object({ value: z.string() })
]),
})
const partialed = mySchema.deepPartial();
type partialed = z.infer<typeof partialed>;
/*
{
name?: string | undefined;
array?: {
asdf?: string | undefined;
}[] | undefined;
tuple?: [{value?: string}] | undefined;
}
*/
Nothing published for this version
Nothing published for this version
Nothing published for this version
Eliminate ZodNonEmptyArray, add Cardinality to ZodArray
ZodNonEmptyArray, add Cardinality to ZodArrayZodArray.nonempty.gt/.gte/.lt/.lte to ZodNumber, alias min -> gte and max -> lteZodError.flatten now optionally accepts a map function for customizing the output
Add IE11 support
ZodError.flatten now optionally accepts a map function for customizing the output
.void() now only accepts undefined, not null.
z.enum now supports Readonly string tuples
const HTTP_SUCCESS = ["200", "201"] as const;
const arg = z.enum(HTTP_SUCCESS);
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
Add discriminator to all first-party schema defs
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →