Hai mai ricevuto dati malformati da un’API esterna e visto la tua app crashare in produzione? O passato ore a debuggare un form che accettava valori impossibili? Zod risolve entrambi i problemi con una sintassi elegante e la type safety di TypeScript al runtime.
Cos’è Zod e Perché Usarlo
Zod è una libreria di validazione TypeScript-first che permette di definire schemi di dati e validarli sia a compile time che a runtime. A differenza di altri validatori, Zod inferisce automaticamente i tipi TypeScript dagli schemi — scrivi lo schema una volta sola e ottieni sia la validazione che i tipi.
npm install zodSchema Base: Oggetti e Tipi Primitivi
Iniziamo con lo schema più comune: validare un oggetto utente come quello che potresti ricevere da un’API REST.
import { z } from 'zod';
const UserSchema = z.object({
id: z.number().int().positive(),
name: z.string().min(2).max(100),
email: z.string().email(),
age: z.number().min(18).max(120).optional(),
role: z.enum(['admin', 'user', 'moderator']),
createdAt: z.string().datetime(),
});
// TypeScript inferisce automaticamente il tipo
type User = z.infer<typeof UserSchema>;
// Equivalente a:
// type User = {
// id: number;
// name: string;
// email: string;
// age?: number | undefined;
// role: 'admin' | 'user' | 'moderator';
// createdAt: string;
// }parse() vs safeParse(): Quale Usare?
Zod offre due modalità di validazione principali. La scelta dipende dal contesto.
// parse() — lancia un'eccezione se la validazione fallisce
try {
const user = UserSchema.parse(rawData);
// user è tipato correttamente
} catch (error) {
if (error instanceof z.ZodError) {
console.error(error.errors); // Array di errori dettagliati
}
}
// safeParse() — ritorna un oggetto result senza eccezioni
const result = UserSchema.safeParse(rawData);
if (result.success) {
const user = result.data; // tipato
} else {
console.error(result.error.errors); // errori di validazione
}💡 Pro tip: Usa
parse()quando sei sicuro che i dati siano validi (es. all’avvio dell’app per validare le env variables). UsasafeParse()per input utente e dati da API esterne dove un errore è un caso normale da gestire.
Validare le Variabili d’Ambiente
Uno dei casi d’uso più potenti di Zod: validare le env variables all’avvio. Se manca una variabile critica, l’app si blocca immediatamente con un messaggio chiaro invece di crashare in produzione con un errore criptico.
// env.ts
import { z } from 'zod';
const EnvSchema = z.object({
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(32),
PORT: z.string().transform(Number).pipe(z.number().int().positive()),
NODE_ENV: z.enum(['development', 'production', 'test']),
STRIPE_SECRET: z.string().startsWith('sk_'),
});
export const env = EnvSchema.parse(process.env);
// Se manca DATABASE_URL → errore immediato all'avvio, non in produzioneIntegrazione con Next.js App Router e Server Actions
Zod si integra perfettamente con le Next.js 16 Server Actions per validare i dati dei form lato server.
// app/actions/contact.ts
'use server';
import { z } from 'zod';
const ContactSchema = z.object({
name: z.string().min(2, 'Nome troppo corto').max(100),
email: z.string().email('Email non valida'),
message: z.string().min(10, 'Messaggio troppo corto').max(1000),
});
export async function submitContact(formData: FormData) {
const rawData = {
name: formData.get('name'),
email: formData.get('email'),
message: formData.get('message'),
};
const result = ContactSchema.safeParse(rawData);
if (!result.success) {
return {
error: result.error.flatten().fieldErrors
// { name: ['Nome troppo corto'], email: ['Email non valida'] }
};
}
// result.data è tipato e validato
await sendEmail(result.data);
return { success: true };
}Schema per API REST: Validare le Response
Validare le response di API esterne è uno dei casi più critici. Con Zod integrato con TypeScript 5, hai type safety completa end-to-end.
import { z } from 'zod';
const ProductSchema = z.object({
id: z.string().uuid(),
name: z.string(),
price: z.number().positive(),
category: z.string(),
tags: z.array(z.string()),
metadata: z.record(z.string(), z.unknown()).optional(),
});
const ProductListSchema = z.array(ProductSchema);
async function fetchProducts(): Promise<z.infer<typeof ProductListSchema>> {
const res = await fetch('/api/products');
const data = await res.json();
return ProductListSchema.parse(data); // Lancia se la risposta è malformata
}Trasformazioni e Preprocessing
Zod non è solo validazione — puoi trasformare i dati durante il parsing. Utile per normalizzare input, convertire tipi e calcolare valori derivati.
const SlugSchema = z.string()
.min(1)
.transform(s => s.toLowerCase().trim().replace(/\s+/g, '-'));
const DateSchema = z.string().datetime()
.transform(s => new Date(s));
const PriceSchema = z.string()
.transform(s => parseFloat(s))
.pipe(z.number().positive());
// Combina validazione e trasformazione
const FormSchema = z.object({
title: z.string().transform(s => s.trim()),
slug: SlugSchema,
publishAt: DateSchema,
price: PriceSchema,
});FAQ e Domande Frequenti
Zod vs Yup vs Joi: quale scegliere nel 2026?
Per progetti TypeScript, Zod è la scelta migliore: inferenza automatica dei tipi, bundle size minore di Yup, API più ergonomica di Joi. Yup rimane valido per progetti React esistenti con react-hook-form. Joi è prevalentemente Node.js e non TypeScript-first.
Zod rallenta l’applicazione?
Il costo è trascurabile per la maggior parte delle applicazioni. Zod è ottimizzato per le performance e valida migliaia di oggetti al secondo. Il costo di validazione è ampiamente ripagato dalla sicurezza e dal debug time risparmiato.
Posso usare Zod con tRPC?
Sì, Zod è il validatore di default di tRPC. Tutti i procedure input vengono validati automaticamente con schemi Zod, ottenendo type safety completa client-server senza duplicare la logica di validazione.
Come gestisco schemi complessi con dipendenze tra campi?
Usa z.refine() o z.superRefine() per validazioni che dipendono da più campi. Esempio: password e conferma password devono essere uguali — z.object({...}).refine(data => data.password === data.confirmPassword).
🔧 Strumenti: zod.dev · react-hook-form + zodResolver · tRPC (usa Zod nativamente) · @conform-to/zod per Remix | 🎯 Takeaway: Definisci lo schema una volta, ottieni validazione runtime + tipi TypeScript gratis. Inizia validando le env variables — è il guadagno immediato più alto.

