Skip to Content
advanced-8y4qeprCommon Patterns

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 required

Optional 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 element

Add 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