Zod: Runtime Validation That Catches Production Bugs TypeScript Misses
TypeScript types disappear at runtime. Zod validates data at the boundaries of your system where TypeScript can't.
The Problem
// TypeScript trusts you here — but what if the API returns something unexpected?
const user: User = await fetch('/api/user').then(r => r.json());
// user.age is typed as number, but the API might return '25' (string)
// TypeScript has no idea. Zod catches this.
Schema Definition
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(100),
email: z.string().email(),
role: z.enum(['admin', 'user', 'moderator']),
});
type User = z.infer<typeof UserSchema>; // Single source of truth
API Request Validation
app.post('/api/posts', async (req, res) => {
const result = CreatePostSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: 'Validation failed',
details: result.error.flatten().fieldErrors,
});
}
const post = await db.posts.create({ data: result.data });
res.json(post);
});
Transformations
const QuerySchema = z.object({
// Coerce string '10' to number 10 (URL params are always strings)
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
});
The Full Stack
Zod + tRPC + Prisma: every layer is validated and typed end-to-end. This stack is pre-wired in the AI SaaS Starter Kit — stop plumbing the same foundation from scratch.
Top comments (0)