MCPcopy Create free account
hub / github.com/colinhacks/zod

github.com/colinhacks/zod

Chat with this repo
repository ↗ · DeepWiki ↗ · release v4.5.0 ↗ · + Follow · compare 4 versions
2,953 symbols 8,837 edges 493 files 107 documented · 4% updated todayv4.4.3 · 2026-05-04★ 43,54456 open issues

Browse by type

Functions 2,104 Types & classes 849
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Zod logo

Zod

TypeScript-first schema validation with static type inference



by <a href="https://x.com/colinhacks">@colinhacks</a>

Zod CI status License npm discord server stars

Docs   •   Discord   •   𝕏   •   Bluesky

Read the docs →

What is Zod?

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);

Features

  • Zero external dependencies
  • Works in Node.js and all modern browsers
  • Tiny: 2kb core bundle (gzipped)
  • Immutable API: methods return a new instance
  • Concise interface
  • Works with TypeScript and plain JS
  • Built-in JSON Schema conversion
  • Extensive ecosystem

Installation

npm install zod

Basic usage

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(),
});

Parsing data

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"

AOT compilation

Canary only — compilation has not shipped in a stable release yet. Install with npm install zod@canary.

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:

  • Compilation uses 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.
  • Schemas with async refinements or transforms can't be compiled, and neither can a few other constructs. That is not an error: 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.
  • On invalid input, refinements and transforms may run twice (fast path, then fallback).
  • Deriving a new schema from a compiled one (.refine(), .extend(), etc.) returns an uncompiled schema — compile the final schema.

See compile docs for details.

Handling errors

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" }

Inferring types

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

Extension points exported contracts — how you extend this code

browse all types & interfaces →

Core symbols most depended-on inside this repo

browse all functions →

Shape

Function 1,656
Interface 678
Method 448
Class 146
Enum 25

Languages

TypeScript100%

Modules by API surface

packages/zod/src/v4/classic/schemas.ts415 symbols
packages/zod/src/v3/types.ts365 symbols
packages/zod/src/v4/core/schemas.ts284 symbols
packages/zod/src/v4/mini/schemas.ts207 symbols
packages/zod/src/v4/core/api.ts123 symbols
packages/zod/src/v4/core/compile.ts82 symbols
packages/zod/src/v4/core/util.ts80 symbols
packages/zod/src/v4/core/checks.ts71 symbols
packages/zod/src/v4/core/json-schema-processors.ts43 symbols
packages/zod/src/v4/core/errors.ts35 symbols
packages/zod/src/v4/classic/tests/recursive-types.test.ts35 symbols
packages/zod/src/v3/ZodError.ts29 symbols

Dependencies from manifests, versioned

@ai-sdk/openai3.0.2 · 1×
@arethetypeswrong/cli0.17.4 · 1×
@biomejs/biome1.9.4 · 1×
@inkeep/cxkit-react0.5.117 · 1×
@radix-ui/react-accordion1.2.4 · 1×
@rollup/plugin-commonjs29.0.2 · 1×
@rollup/plugin-node-resolve16.0.1 · 1×
@rollup/plugin-terser1.0.0 · 1×
@seriousme/openapi-schema-validator2.9.0 · 1×
@types/benchmark2.1.5 · 1×

Datastores touched

(mongodb)Database · 1 repos
defaultauthdbDatabase · 1 repos

For agents

$ claude mcp add zod \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page