Schemas

A schema defines the shape and constraints of your data. Zod schemas are composable - build complex types from simple ones.

Primitive Schemas

import { z } from "zod";

z.string();
z.number();
z.boolean();
z.date();
z.undefined();
z.null();
z.literal("active");  // exact value

Object Schemas

const UserSchema = z.object({
  name: z.string(),
  email: z.string().email(),
  age: z.number().min(0).max(150),
});

type User = z.infer<typeof UserSchema>;
// { name: string; email: string; age: number }

Composing Schemas

Optional and nullable

z.string().optional();           // string | undefined
z.string().nullable();           // string | null
z.string().nullish();            // string | null | undefined
z.string().default("unnamed");   // defaults if undefined

Arrays

z.array(z.string());             // string[]
z.array(z.number()).min(1);      // at least one element
z.string().array();              // same as z.array(z.string())

Unions and enums

z.union([z.string(), z.number()]);     // string | number
z.enum(["active", "inactive"]);         // "active" | "inactive"
z.nativeEnum(Direction);                 // from TypeScript enum

Extending objects

const BaseSchema = z.object({ id: z.string() });
const UserSchema = BaseSchema.extend({ name: z.string() });
// { id: string; name: string }

const PartialUser = UserSchema.partial();      // all fields optional
const PickedUser = UserSchema.pick({ name: true }); // { name: string }
const OmittedUser = UserSchema.omit({ id: true });  // { name: string }

Tip: Zod’s .extend(), .pick(), .omit(), and .partial() mirror TypeScript utility types but work at runtime too.