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.