
Research
/Security News
OpenAPI React Query Codegen Compromised in Mini Shai-Hulud npm Supply Chain Attack
Ten malicious OpenAPI React Query Codegen versions were published to npm in the Mini Shai-Hulud attack, all with valid provenance.
TypeScript-first schema validation with static type inference
by @colinhacks
Zod is a TypeScript-first validation library. Define a schema and parse some data with it. You'll get back a strongly typed, validated result.
import * as z from "zod";
const User = z.object({
name: z.string(),
});
// some untrusted data...
const input = {
/* stuff */
};
// the parsed result is validated and type safe!
const data = User.parse(input);
// so you can use it with confidence :)
console.log(data.name);
2kb core bundle (gzipped)npm install zod
Before you can do anything else, you need to define a schema. For the purposes of this guide, we'll use a simple object schema.
import * as z from "zod";
const Player = z.object({
username: z.string(),
xp: z.number(),
});
Given any Zod schema, use .parse to validate an input. If it's valid, Zod returns a strongly-typed deep clone of the input.
Player.parse({ username: "billie", xp: 100 });
// => returns { username: "billie", xp: 100 }
Note — If your schema uses certain asynchronous APIs like async refinements or transforms, you'll need to use the .parseAsync() method instead.
const schema = z.string().refine(async (val) => val.length <= 8);
await schema.parseAsync("hello");
// => "hello"
For hot validation paths, z.compile(schema) returns a schema clone with an ahead-of-time compiled fast path. Valid inputs take the compiled path; invalid inputs fall back to the regular parser so error reporting stays identical.
Across a 55-schema benchmark the median speedup is 2.4x, and it scales with how much work the schema does per parse: a large array of objects is ~9x, a 20-key object ~9x, a nested object ~4.5x, while a bare z.string() gains nothing — compilation removes per-node dispatch and allocation, and a single typeof has none to remove.
const CompiledPlayer = z.compile(Player);
CompiledPlayer.parse({ username: "billie", xp: 100 });
To enable compilation globally for schemas constructed after import:
import "zod/compile"; // place before modules that define schemas
Things to know:
new Function. Global mode is automatically disabled when z.config({ jitless: true }) is set (e.g. CSP environments); calling z.compile() directly is an explicit opt-in.z.compile() hands the schema back unchanged and it keeps using the regular parser, exactly as global mode leaves it. Pass { strict: true } to throw ZodCompileAsyncError / ZodCompileUnsupportedError instead..refine(), .extend(), etc.) returns an uncompiled schema — compile the final schema.See compile docs for details.
When validation fails, the .parse() method will throw a ZodError instance with granular information about the validation issues.
try {
Player.parse({ username: 42, xp: "100" });
} catch (err) {
if (err instanceof z.ZodError) {
err.issues;
/* [
{
expected: 'string',
code: 'invalid_type',
path: [ 'username' ],
message: 'Invalid input: expected string'
},
{
expected: 'number',
code: 'invalid_type',
path: [ 'xp' ],
message: 'Invalid input: expected number'
}
] */
}
}
To avoid a try/catch block, you can use the .safeParse() method to get back a plain result object containing either the successfully parsed data or a ZodError. The result type is a discriminated union, so you can handle both cases conveniently.
const result = Player.safeParse({ username: 42, xp: "100" });
if (!result.success) {
result.error; // ZodError instance
} else {
result.data; // { username: string; xp: number }
}
Note — If your schema uses certain asynchronous APIs like async refinements or transforms, you'll need to use the .safeParseAsync() method instead.
const schema = z.string().refine(async (val) => val.length <= 8);
await schema.safeParseAsync("hello");
// => { success: true; data: "hello" }
Zod infers a static type from your schema definitions. You can extract this type with the z.infer<> utility and use it however you like.
const Player = z.object({
username: z.string(),
xp: z.number(),
});
// extract the inferred type
type Player = z.infer<typeof Player>;
// use it in your code
const player: Player = { username: "billie", xp: 100 };
In some cases, the input & output types of a schema can diverge. For instance, the .transform() API can convert the input from one type to another. In these cases, you can extract the input and output types independently:
const mySchema = z.string().transform((val) => val.length);
type MySchemaIn = z.input<typeof mySchema>;
// => string
type MySchemaOut = z.output<typeof mySchema>; // equivalent to z.infer<typeof mySchema>
// number
Joi is a powerful schema description language and data validator for JavaScript. It offers a similar API to Zod but has been around longer and is often considered more mature. Joi provides a wide range of built-in validators and is highly extensible.
Yup is a JavaScript schema builder for value parsing and validation. It defines a schema with an expressive API and can be used with or without TypeScript. Yup is often used in the context of form validation, especially with libraries like Formik.
Ajv is a JSON Schema Validator. It validates data against JSON Schema (draft 06/07/2019) and is known for its performance. Unlike Zod, which is TypeScript-first, Ajv focuses on JSON Schema validation and is often used for validating data structures in RESTful APIs.
Class-validator allows for validation of class instances based on decorators. It is tightly coupled with TypeScript and uses decorators to define validation rules, which can be more familiar to developers used to working with TypeScript classes and decorators.
FAQs
TypeScript-first schema declaration and validation library with static type inference
The npm package zod receives a total of 250,088,840 weekly downloads. As such, zod popularity was classified as popular.
We found that zod demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Ten malicious OpenAPI React Query Codegen versions were published to npm in the Mini Shai-Hulud attack, all with valid provenance.

Security News
Socket joins more than 100 technology, cybersecurity, and financial organizations calling for a global surge in cyber defense.

Product
Enterprise security teams can now detect malware, credential theft, suspicious network activity, and risky updates across Microsoft Edge extensions.