Basic Usage
Install
npm install zod
Define a Schema
import { z } from "zod";
const ProductSchema = z.object({
name: z.string(),
price: z.number().nonnegative(),
tags: z.array(z.string()),
});
Validate Data
// .parse() throws on invalid data
const product = ProductSchema.parse({
name: "Widget",
price: 9.99,
tags: ["tools"],
});
// .safeParse() returns a result object (no throw)
const result = ProductSchema.safeParse(input);
if (result.success) {
console.log(result.data); // typed as Product
} else {
console.log(result.error.issues); // validation errors
}
Tip: Use
.safeParse()in production code. It’s easier to handle errors without try/catch.
Infer TypeScript Types
type Product = z.infer<typeof ProductSchema>;
// { name: string; price: number; tags: string[] }
// Use the type like any other TypeScript type
function displayProduct(product: Product) {
console.log(`${product.name}: $${product.price}`);
}
Common Patterns
Form validation
const LoginSchema = z.object({
email: z.string().email("Invalid email"),
password: z.string().min(8, "Password must be at least 8 characters"),
});
const result = LoginSchema.safeParse(formData);
if (!result.success) {
const errors = result.error.flatten().fieldErrors;
// { email?: string[], password?: string[] }
}
API response validation
const ApiResponse = z.object({
data: z.array(ProductSchema),
total: z.number(),
page: z.number(),
});
const response = await fetch("/api/products");
const validated = ApiResponse.parse(await response.json());
Environment variables
const EnvSchema = z.object({
DATABASE_URL: z.string().url(),
PORT: z.coerce.number().default(3000),
NODE_ENV: z.enum(["development", "production", "test"]),
});
const env = EnvSchema.parse(process.env);
Gotcha:
z.coerce.number()converts strings to numbers (useful for env vars and query params). Plainz.number()rejects strings.