Zod 4 es una reescritura completa de la librería de validación más popular de TypeScript, ofreciendo hasta 10x más velocidad en parsing, un bundle más pequeño y nuevas APIs potentes. Si estás construyendo formularios, rutas API o cualquier frontera de datos en tu app Next.js, Zod 4 es la herramienta que mantiene tus tipos en runtime sincronizados con TypeScript — automáticamente.
¿Qué hay de nuevo en Zod 4?
Zod 4 no es una actualización incremental — es una reescritura completa centrada en rendimiento y experiencia de desarrollo:
- 10x más rápido en parsing: Reescritura completa del motor interno de validación.
- Bundle más pequeño: Diseño tree-shakeable, solo pagas por lo que usas.
z.interface(): Una nueva forma de definir schemas de objetos con mejor inferencia TypeScript.z.templateLiteral(): Valida strings de template literal como`user_${number}`.- JSON Schema output: Método nativo
.toJsonSchema()en cada schema. - Mejores mensajes de error: Formato rediseñado con soporte i18n.
Schemas Básicos
Si has usado Zod antes, la API core es familiar — pero todo es más rápido internamente:
import { z } from 'zod';
// Schemas primitivos
const nameSchema = z.string().min(2).max(100);
const ageSchema = z.number().int().gte(18);
const emailSchema = z.string().email();
const isActiveSchema = z.boolean();
// Schema de objeto
const UserSchema = z.object({
name: nameSchema,
email: emailSchema,
age: ageSchema.optional(),
role: z.enum(['admin', 'editor', 'viewer']),
isActive: isActiveSchema.default(true),
});
// Tipo TypeScript inferido — siempre sincronizado
type User = z.infer<typeof UserSchema>;
// { name: string; email: string; age?: number; role: 'admin' | 'editor' | 'viewer'; isActive: boolean }El nuevo z.interface()
Zod 4 introduce z.interface() que proporciona mejor inferencia TypeScript para tipos recursivos y complejos:
// Tipos recursivos (ej. un árbol de comentarios)
const CommentSchema = z.interface({
id: z.number(),
body: z.string(),
author: z.string(),
// Auto-referencia — z.interface() maneja esto nativamente
replies: z.array(z.lazy(() => CommentSchema)).default([]),
});
type Comment = z.infer<typeof CommentSchema>;
// { id: number; body: string; author: string; replies: Comment[] }Tipos Template Literal
Una de las funcionalidades más solicitadas — valida strings que siguen un patrón:
// Validar formatos de string estructurados
const userIdSchema = z.templateLiteral([z.literal('user_'), z.number()]);
// Acepta: 'user_123', 'user_0', 'user_99999'
// Rechaza: 'user_abc', 'admin_123', '123'
const hexColorSchema = z.templateLiteral([
z.literal('#'),
z.string().regex(/^[0-9a-fA-F]{6}$/),
]);
// Acepta: '#ff0000', '#1a2b3c'Salida JSON Schema
Cada schema de Zod 4 puede convertirse a JSON Schema — útil para documentación de API, specs OpenAPI o definiciones de herramientas de IA:
const ProductSchema = z.object({
name: z.string().min(1).describe('Nombre del producto'),
price: z.number().positive().describe('Precio en céntimos'),
category: z.enum(['electronics', 'books', 'clothing']),
});
const jsonSchema = ProductSchema.toJsonSchema();
// {
// type: 'object',
// properties: {
// name: { type: 'string', minLength: 1, description: 'Nombre del producto' },
// price: { type: 'number', exclusiveMinimum: 0, description: 'Precio en céntimos' },
// category: { type: 'string', enum: ['electronics', 'books', 'clothing'] }
// },
// required: ['name', 'price', 'category']
// }Zod 4 con React Hook Form
La integración con React Hook Form vía @hookform/resolvers funciona igual, pero ahora con el rendimiento mejorado de Zod 4:
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const ContactSchema = z.object({
name: z.string().min(2, 'El nombre debe tener al menos 2 caracteres'),
email: z.string().email('Introduce un email válido'),
message: z.string().min(10, 'El mensaje debe tener al menos 10 caracteres'),
});
type ContactForm = z.infer<typeof ContactSchema>;
export function ContactForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<ContactForm>({
resolver: zodResolver(ContactSchema),
});
const onSubmit = (data: ContactForm) => {
// data está totalmente tipado y validado
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('name')} placeholder="Nombre" />
{errors.name && <p>{errors.name.message}</p>}
<input {...register('email')} placeholder="Email" />
{errors.email && <p>{errors.email.message}</p>}
<textarea {...register('message')} placeholder="Mensaje" />
{errors.message && <p>{errors.message.message}</p>}
<button type="submit">Enviar</button>
</form>
);
}Validación en Server Actions
Usa Zod para validar datos de formulario en tus Server Actions de Next.js — un schema, validado tanto en cliente como en servidor:
// app/actions.ts
'use server';
import { z } from 'zod';
const CreatePostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(10),
tags: z.array(z.string()).max(5),
published: z.boolean().default(false),
});
export async function createPost(formData: FormData) {
const raw = {
title: formData.get('title'),
content: formData.get('content'),
tags: formData.getAll('tags'),
published: formData.get('published') === 'true',
};
const result = CreatePostSchema.safeParse(raw);
if (!result.success) {
return {
errors: result.error.flatten().fieldErrors,
};
}
// result.data está totalmente tipado como CreatePost
await db.post.create({ data: result.data });
revalidatePath('/posts');
}Validación en Route Handlers
Para rutas API, Zod asegura que tus request bodies siempre tengan la forma que esperas:
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
const CreateUserBody = z.object({
name: z.string().min(2),
email: z.string().email(),
role: z.enum(['admin', 'user']).default('user'),
});
export async function POST(req: NextRequest) {
const body = await req.json();
const parsed = CreateUserBody.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: parsed.error.flatten() },
{ status: 400 }
);
}
// parsed.data está tipado como { name: string; email: string; role: 'admin' | 'user' }
const user = await createUser(parsed.data);
return NextResponse.json(user, { status: 201 });
}Migrando desde Zod 3
La migración de Zod 3 a Zod 4 es mayormente transparente, pero estos son los cambios clave:
z.object()sigue funcionando —z.interface()es aditivo, no un reemplazo.- El formato de errores ha cambiado — revisa tus manejadores de error personalizados.
.toJsonSchema()reemplaza el paquetezod-to-json-schema.- Algunos casos edge en
.transform()y.pipe()se comportan diferente — testea tus pipelines. - El bundle es más pequeño, pero asegúrate de importar desde
'zod'(no rutas profundas).
Conclusión
Zod 4 consolida su posición como la librería esencial de validación en TypeScript. Con parsing 10x más rápido, salida nativa de JSON Schema y nuevas APIs como z.interface() y z.templateLiteral(), es la mejor forma de validar datos en cada frontera de tu aplicación Next.js — desde formularios hasta rutas API y Server Actions.