SponsorsTable of ContentsGetting StartedInstallationMigration guide
Usage
CoerceLiteralsStringsNumbersBigIntsNaNsBooleansDatesEnumsOptionalsNullablesObjectsArraysUnionsRecordsMapsSetsIntersectionsRecursive typesPromisesInstanceofFunctionsPreprocess
Schema methods
Custom schemas
Guides and Concepts
Error HandlingComparisonEcosystem
Contributing
ChangelogCode of ConductLICENSE
Links
Clerk
⌘+J

© 2025 Zod


Designed in Earth-616

Build by oeri

Usage

Basic Usage

Zod provides a simple API to define and validate data schemas. This section covers the fundamental usage of Zod, including schema creation, parsing, and type inference.

Creating a Simple String Schema

Import z from Zod:

import { z } from "zod";

Define a basic string schema:

const mySchema = z.string();

Parsing Values

You can validate data using the .parse() method:

mySchema.parse("tuna"); // => "tuna"
mySchema.parse(12); // Throws ZodError

If the input is invalid, parse throws an error. To handle errors gracefully, use .safeParse():

mySchema.safeParse("tuna");
// => { success: true, data: "tuna" }
 
mySchema.safeParse(12);
/* =>
{
  success: false,
  error: ZodError
}
*/

Defining Object Schemas

Zod allows you to define schemas for structured objects.

const User = z.object({
  username: z.string(),
  age: z.number()
});

Parsing an Object

User.parse({ username: "Alice", age: 25 }); // Valid ✅
User.parse({ username: "Alice", age: "25" }); // Throws ZodError ❌

Inferring TypeScript Types

Zod schemas can infer TypeScript types automatically:

type User = z.infer<typeof User>;
/* Equivalent to:
type User = {
  username: string;
  age: number;
}
*/

Primitive Types in Zod

Zod provides built-in validation for JavaScript primitive types.

z.string(); // Validates a string
z.number(); // Validates a number
z.bigint(); // Validates a bigint
z.boolean(); // Validates a boolean
z.date(); // Validates a Date object
z.symbol(); // Validates a symbol

Handling Special Types

Empty Types

Zod has built-in support for values that represent emptiness.

z.undefined(); // Matches undefined
z.null(); // Matches null
z.void(); // Matches undefined (useful for function return types)

Catch-All Types

These schemas accept any value.

z.any(); // Accepts any value
z.unknown(); // Similar to `any` but forces type checking in TypeScript

Never Type

A never schema ensures that no value is valid.

z.never(); // Always fails validation

Advanced Schema Composition

Zod enables you to create more complex schemas by combining basic ones.

Array Schema

Validate an array of a specific type.

const NumberArray = z.array(z.number());
 
NumberArray.parse([1, 2, 3]); // ✅ Valid
NumberArray.parse(["one", 2, 3]); // ❌ Throws ZodError

Tuple Schema

Fixed-length arrays with specific types for each element.

const myTuple = z.tuple([z.string(), z.number()]);
 
myTuple.parse(["hello", 42]); // ✅ Valid
myTuple.parse([42, "hello"]); // ❌ Throws ZodError

Union Types

Allow multiple possible data types.

const StringOrNumber = z.union([z.string(), z.number()]);
 
StringOrNumber.parse("hello"); // ✅ Valid
StringOrNumber.parse(123); // ✅ Valid
StringOrNumber.parse(true); // ❌ Throws ZodError

Intersection Types

Combine two schemas into one.

const Person = z.object({ name: z.string() });
const Age = z.object({ age: z.number() });
 
const PersonWithAge = Person.and(Age);
 
PersonWithAge.parse({ name: "Alice", age: 30 }); // ✅ Valid
PersonWithAge.parse({ name: "Alice" }); // ❌ Throws ZodError

Optional and Nullable Fields

Making a Field Optional

const User = z.object({
  username: z.string(),
  bio: z.string().optional()
});
 
User.parse({ username: "Alice" }); // ✅ Valid (bio is optional)
User.parse({ username: "Alice", bio: "Hello" }); // ✅ Valid
User.parse({ bio: "Hello" }); // ❌ Invalid (username is required)

Allowing Null Values

const Post = z.object({
  title: z.string(),
  content: z.string().nullable()
});
 
Post.parse({ title: "Hello", content: null }); // ✅ Valid
Post.parse({ title: "Hello", content: "Text" }); // ✅ Valid
Post.parse({ title: "Hello" }); // ❌ Invalid (content is required)

Refining and Custom Validations

Using .refine() for Custom Validation

You can add additional constraints beyond basic type checking.

const PositiveNumber = z.number().refine(n => n > 0, {
  message: "Number must be positive"
});
 
PositiveNumber.parse(10); // ✅ Valid
PositiveNumber.parse(-5); // ❌ Throws ZodError ("Number must be positive")

Using .superRefine() for More Complex Validations

const Password = z.string().superRefine((val, ctx) => {
  if (val.length < 8) {
    ctx.addIssue({
      code: "custom",
      message: "Password must be at least 8 characters long"
    });
  }
});
 
Password.parse("short"); // ❌ Throws ZodError
Password.parse("longenoughpassword"); // ✅ Valid

Transforming Data

Zod allows you to modify values during validation.

const TrimmedString = z.string().transform(str => str.trim());
 
TrimmedString.parse("  hello  "); // ✅ "hello"

Chaining multiple transformations:

const UserName = z.string().trim().toLowerCase();
 
UserName.parse("  ALICE  "); // ✅ "alice"

Asynchronous Validations

Zod supports async validation, useful for database lookups or API calls.

const EmailSchema = z
  .string()
  .email()
  .refine(async email => {
    const isAvailable = await checkEmailAvailability(email);
    return isAvailable;
  }, "Email is already taken");
 
EmailSchema.parseAsync("user@example.com").then(console.log).catch(console.error);

Conclusion

Zod provides a rich set of features for defining, validating, and transforming data with minimal effort. Whether you're working with form validation, API request handling, or TypeScript type safety, Zod is a powerful tool that simplifies data management.

To explore more advanced features and real-world use cases, check out Table of Contents.

On This Page

Usage
Basic usage
Creating a simple string schema
Parsing values
Defining object schemas
Parsing an object
Inferring typescript types
Primitive types in zod
Handling special types
Empty types
Catch All types
Never type
Advanced schema composition
Array schema
Tuple schema
Union types
Intersection types
Optional and nullable fields
Making a field optional
Allowing null values
Refining and custom validations
Using .refine() for custom validation
Using .superrefine() for more complex validations
Transforming data
Asynchronous validations
Conclusion

Edit this page on GitHub