Zod lets you define schemas once and get TypeScript types, runtime validation, and error messages automatically.
The Validation Problem
TypeScript types disappear at runtime. Your API receives any. Your form data is unknown. You write validation logic AND types — and keep them in sync manually.
Zod: define the schema once, get both the type and the validator.
What You Get for Free
Schema = Type + Validator:
import { z } from 'zod';
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive().optional(),
});
// Extract TypeScript type automatically
type User = z.infer<typeof UserSchema>;
// { name: string; email: string; age?: number }
// Runtime validation
const result = UserSchema.safeParse(unknownData);
if (result.success) {
console.log(result.data); // fully typed as User
} else {
console.log(result.error.issues); // detailed error messages
}
Why Zod Won
Zero dependencies — 0 external deps, ~13KB gzipped
Works everywhere — browser, Node, Deno, Bun, edge functions
Composable schemas — .extend(), .merge(), .pick(), .omit(), .partial()
Transforms — parse and transform in one step:
const DateSchema = z.string().transform((s) => new Date(s));
// Input: string, Output: Date
Ecosystem integrations:
- tRPC — uses Zod for input validation
-
React Hook Form —
@hookform/resolvers/zod - Next.js Server Actions — validate form submissions
- Hono — route validation middleware
- Astro — content collection schemas
Advanced Patterns
// Discriminated unions
const Shape = z.discriminatedUnion('type', [
z.object({ type: z.literal('circle'), radius: z.number() }),
z.object({ type: z.literal('square'), side: z.number() }),
]);
// Recursive types
const Category: z.ZodType<Category> = z.object({
name: z.string(),
children: z.lazy(() => Category.array()),
});
// Branded types (nominal typing)
const UserId = z.string().uuid().brand<'UserId'>();
type UserId = z.infer<typeof UserId>;
Quick Start
npm install zod
One dependency. No config. No codegen. Start validating.
If you're writing TypeScript and NOT using Zod — you're maintaining duplicate type definitions.
Need web scraping or data extraction? Check out my tools on Apify — get structured data from any website in minutes.
Custom solution? Email spinov001@gmail.com — quote in 2 hours.
Top comments (0)