The Validation Problem
You define a TypeScript type. Then you write a Joi schema. Then you realize they're out of sync. Your API accepts data that crashes your app.
Zod defines the schema once and infers the TypeScript type. Single source of truth.
What Zod Gives You
Schema = Type
import { z } from 'zod';
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive().optional(),
});
// TypeScript type is INFERRED — no manual interface needed
type User = z.infer<typeof UserSchema>;
// { name: string; email: string; age?: number }
Change the schema → the type updates automatically.
Parse, Don't Validate
// Throws on invalid data
const user = UserSchema.parse(requestBody);
// user is fully typed as User
// Or get errors without throwing
const result = UserSchema.safeParse(requestBody);
if (result.success) {
console.log(result.data.name); // typed
} else {
console.log(result.error.issues); // detailed errors
}
API Request Validation
const CreatePostSchema = z.object({
title: z.string().min(1).max(200),
body: z.string().min(10),
tags: z.array(z.string()).max(5),
publishedAt: z.string().datetime().optional(),
});
app.post('/posts', (req, res) => {
const result = CreatePostSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.flatten() });
}
// result.data is fully typed and validated
createPost(result.data);
});
Transform Data
const StringToNumber = z.string().transform(Number);
const result = StringToNumber.parse('42'); // 42 (number)
const Trimmed = z.string().trim().toLowerCase();
const email = Trimmed.parse(' User@Email.COM '); // 'user@email.com'
Discriminated Unions
const EventSchema = z.discriminatedUnion('type', [
z.object({ type: z.literal('click'), x: z.number(), y: z.number() }),
z.object({ type: z.literal('scroll'), offset: z.number() }),
z.object({ type: z.literal('keypress'), key: z.string() }),
]);
Works Everywhere
Zod works with: React Hook Form, tRPC, Next.js Server Actions, Remix, Astro, Express, Fastify, Hono — any TypeScript project.
Quick Start
npm install zod
Zero dependencies. 14KB minified. TypeScript required.
Why This Matters
Every API boundary needs validation. Zod makes validation and TypeScript types the same thing. Write it once, get safety everywhere.
Need validated data from external sources? Check out my web scraping actors on Apify Store — structured, clean data for your schemas. For custom solutions, email spinov001@gmail.com.
Top comments (0)