.optional()
Makes a schema accept undefined in addition to its base type.
import { z } from 'zod';
const schema = z.string().optional();
schema.parse('hello'); // 'hello'
schema.parse(undefined); // undefined
schema.parse(null); // throws error
Type Inference
The .optional() modifier affects both input and output types:
const schema = z.string().optional();
type Input = z.input<typeof schema>; // string | undefined
type Output = z.output<typeof schema>; // string | undefined
Unwrapping
You can remove the optional wrapper using .unwrap():
const optional = z.string().optional();
const base = optional.unwrap(); // ZodString
In Object Schemas
Fields with .optional() can be omitted from objects:
const User = z.object({
name: z.string(),
email: z.string().optional(),
});
User.parse({ name: 'John' }); // Valid
User.parse({ name: 'John', email: undefined }); // Valid
User.parse({ name: 'John', email: '[email protected]' }); // Valid
When a field is .optional(), you can omit it entirely from the object. The field will be undefined in the parsed result.
.exactOptional()
Similar to .optional(), but enforces that undefined must be explicitly present in objects rather than being omitted.
const User = z.object({
name: z.string(),
email: z.string().exactOptional(),
});
User.parse({ name: 'John', email: undefined }); // Valid
User.parse({ name: 'John' }); // Invalid - email must be present
Type Inference
const schema = z.string().exactOptional();
type Input = z.input<typeof schema>; // string | undefined
type Output = z.output<typeof schema>; // string | undefined
Use Cases
.optional(): Use when a field can be omitted from objects
.exactOptional(): Use when you want to distinguish between “field not provided” and “field set to undefined”
Chaining with Other Modifiers
// Optional with default
const schema1 = z.string().optional().default('hello');
schema1.parse(undefined); // 'hello'
// Optional with nullable
const schema2 = z.string().optional().nullable();
schema2.parse(undefined); // undefined
schema2.parse(null); // null
// Transform then optional
const schema3 = z.string()
.transform(s => s.toUpperCase())
.optional();
type Input3 = z.input<typeof schema3>; // string | undefined
type Output3 = z.output<typeof schema3>; // string | undefined