docs
guides
reference
This guide will help you get started with Zod in minutes.
npm install zodimport * as z from 'zod';
// or
import { z } from 'zod';const UserSchema = z.object({
name: z.string(),
age: z.number().int().positive(),
email: z.string().email(),
});// Throws ZodError on invalid data
const user = UserSchema.parse({
name: 'Alice',
age: 30,
email: 'alice@example.com',
});
// Returns result object (doesn't throw)
const result = UserSchema.safeParse({
name: 'Bob',
age: 25,
email: 'bob@example.com',
});
if (result.success) {
console.log(result.data); // Validated data
} else {
console.error(result.error.issues); // Validation errors
}type User = z.infer<typeof UserSchema>;
// { name: string; age: number; email: string }const UsernameSchema = z.string()
.min(3, 'Username must be at least 3 characters')
.max(20, 'Username must be at most 20 characters')
.regex(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores');const AgeSchema = z.number()
.int('Age must be an integer')
.min(0, 'Age cannot be negative')
.max(120, 'Age cannot exceed 120');const UserSchema = z.object({
name: z.string(),
email: z.string().email(),
nickname: z.string().optional(), // Optional field
middleName: z.string().nullable(), // Can be null
bio: z.string().nullish(), // Can be null or undefined
});const ConfigSchema = z.object({
port: z.number().default(3000),
host: z.string().default('localhost'),
debug: z.boolean().default(false),
});const TagsSchema = z.array(z.string())
.min(1, 'At least one tag is required')
.max(10, 'Maximum 10 tags allowed');const AddressSchema = z.object({
street: z.string(),
city: z.string(),
country: z.string(),
});
const UserSchema = z.object({
name: z.string(),
address: AddressSchema,
});const StatusSchema = z.enum(['pending', 'active', 'completed']);
// or
const StatusSchema = z.union([
z.literal('pending'),
z.literal('active'),
z.literal('completed'),
]);try {
const data = schema.parse(input);
// Use validated data
} catch (error) {
if (error instanceof z.ZodError) {
// Handle validation errors
console.error('Validation failed:', error.issues);
}
}const result = schema.safeParse(input);
if (result.success) {
// TypeScript knows result.data is valid
console.log(result.data);
} else {
// TypeScript knows result.error exists
console.error(result.error.issues);
}const result = schema.safeParse(input);
if (!result.success) {
// Format as nested object
const formatted = result.error.format();
// { name: { _errors: ['Required'] }, email: { _errors: ['Invalid email'] } }
// Flatten to field errors
const flattened = result.error.flatten();
// { fieldErrors: { name: ['Required'], email: ['Invalid email'] }, formErrors: [] }
}const PasswordSchema = z.string()
.min(8, 'Password must be at least 8 characters')
.refine(
(val) => /[A-Z]/.test(val),
'Password must contain at least one uppercase letter'
)
.refine(
(val) => /[0-9]/.test(val),
'Password must contain at least one number'
);const PasswordSchema = z.string().superRefine((password, ctx) => {
if (password.length < 8) {
ctx.addIssue({
code: 'too_small',
minimum: 8,
type: 'string',
inclusive: true,
message: 'Password must be at least 8 characters',
});
}
if (!/[A-Z]/.test(password)) {
ctx.addIssue({
code: 'custom',
message: 'Password must contain uppercase letter',
});
}
});const StringToNumber = z.string().transform((val) => parseInt(val, 10));
const TrimmedEmail = z.string()
.transform((s) => s.trim().toLowerCase())
.pipe(z.string().email());For form data and URL parameters that come as strings:
const FormSchema = z.object({
name: z.coerce.string(),
age: z.coerce.number().int().min(0),
isActive: z.coerce.boolean(),
birthDate: z.coerce.date(),
});