Last Updated: 3/12/2026
Common Patterns
This guide covers the most frequently used patterns for handling optional fields, nullable values, and defaults in Zod schemas.
Optional Fields
Make a field optional with .optional():
import * as z from "zod";
const User = z.object({
username: z.string(),
age: z.number().optional(),
});
type User = z.infer<typeof User>;
// { username: string; age?: number | undefined }
User.parse({ username: "billie" }); // ✓
User.parse({ username: "billie", age: 25 }); // ✓
User.parse({ username: "billie", age: undefined }); // ✓Nullable Fields
Make a field nullable with .nullable():
const User = z.object({
username: z.string(),
bio: z.string().nullable(),
});
type User = z.infer<typeof User>;
// { username: string; bio: string | null }
User.parse({ username: "billie", bio: null }); // ✓
User.parse({ username: "billie", bio: "Hello!" }); // ✓
User.parse({ username: "billie" }); // ✗ bio is requiredOptional AND Nullable
Use .nullish() to accept both null and undefined:
const User = z.object({
username: z.string(),
bio: z.string().nullish(),
});
type User = z.infer<typeof User>;
// { username: string; bio?: string | null | undefined }
User.parse({ username: "billie" }); // ✓
User.parse({ username: "billie", bio: null }); // ✓
User.parse({ username: "billie", bio: undefined }); // ✓
User.parse({ username: "billie", bio: "Hello!" }); // ✓Default Values
Provide a default value with .default():
const Settings = z.object({
theme: z.enum(["light", "dark"]).default("light"),
notifications: z.boolean().default(true),
});
Settings.parse({});
// => { theme: "light", notifications: true }
Settings.parse({ theme: "dark" });
// => { theme: "dark", notifications: true }Defaults are applied during parsing, not during type inference:
type Settings = z.infer<typeof Settings>;
// { theme: "light" | "dark"; notifications: boolean }
// NOT { theme?: "light" | "dark"; notifications?: boolean }Arrays
Validate arrays with z.array():
const Tags = z.array(z.string());
Tags.parse(["typescript", "zod"]); // ✓
Tags.parse(["typescript", 123]); // ✗ invalid elementAdd length constraints:
const Tags = z.array(z.string())
.min(1, "At least one tag required")
.max(5, "Maximum 5 tags allowed")
.nonempty(); // Alias for .min(1)
Tags.parse([]); // ✗ too short
Tags.parse(["a", "b", "c"]); // ✓Combining Patterns
You can chain these methods together:
const User = z.object({
username: z.string(),
tags: z.array(z.string()).optional().default([]),
bio: z.string().nullable(),
age: z.number().int().positive().optional(),
});
User.parse({ username: "billie", bio: null });
// => { username: "billie", tags: [], bio: null }What’s Next
- Defining Schemas — Explore all available schema types
- Error Handling — Learn how to handle validation errors