Cuándo usar Zod en lugar de TypeScript para validación en runtime
Zod vs TypeScript puro: cuándo usar validación en runtime
¿Confías en TypeScript para proteger tu app en producción? Deja de hacerlo. TypeScript es un analizador estático; su trabajo termina cuando el código se compila. Si quieres seguridad real en ejecución necesitas otra cosa. Aquí va la guía práctica: Zod vs TypeScript puro: cuándo usar validación en runtime.
TypeScript ordena tu código. Zod protege tus fronteras. Úsalos juntos, no en guerra.
Tiempo estimado de lectura: 4 min
- TypeScript es un analizador estático: no protege en runtime.
- Zod parsea en runtime y mantiene una sola fuente de verdad con z.infer.
- Valida en las fronteras (endpoints, webhooks, env, uploads); confía en TypeScript dentro del dominio.
- Mide impacto de rendimiento y evita validaciones redundantes en el core.
¿Confías en TypeScript para proteger tu app en producción? Deja de hacerlo. TypeScript es un analizador estático; su trabajo termina cuando el código se compila. Si quieres seguridad real en ejecución necesitas otra cosa. Aquí va la guía práctica: Zod vs TypeScript puro: cuándo usar validación en runtime.
Resumen rápido (lectores con prisa)
Qué es: Zod es una librería de validación y parsing en runtime; TypeScript es un sistema de tipos estático.
Cuándo usarlo: Usa Zod en las fronteras (endpoints, webhooks, env, uploads); usa TypeScript dentro del dominio.
Por qué importa: TypeScript sufre type erasure y no impide fallos en producción; Zod parsea y falla rápido.
Cómo usarlo: Definir esquemas Zod, derivar tipos con z.infer y parsear payloads en los handlers.
Por qué TypeScript no basta (y dónde duele más)
TypeScript tiene un problema estructural: Type Erasure. Los tipos desaparecen al compilar. Eso significa que las aserciones (as T) son mentiras que el compilador acepta y la app paga en runtime.
interface Usuario { id: number; email: string; }
const datos = await respuesta.json() as Usuario;
console.log(datos.email.toLowerCase()); // Boom si email no existe
Si la API cambia, o devuelve HTML en un error 500, tu código explota. TypeScript no está ahí para detenerlo.
Zod y el principio “Parse, don’t validate”
Zod opera en runtime. Su filosofía es clara: no intentes “validar” por inercia; parsea y falla rápido.
import { z } from 'zod';
const UsuarioSchema = z.object({
id: z.number(),
email: z.string().email(),
});
type Usuario = z.infer;
const res = await fetch(url);
const raw = await res.json();
const usuario = UsuarioSchema.parse(raw); // lanza si algo falla
console.log(usuario.email.toLowerCase());
Con z.infer mantienes una sola fuente de verdad: el esquema. Nada de duplicar interfaces y validadores.
safeParse vs parse
Si quieres manejo de errores controlado:
const result = UsuarioSchema.safeParse(raw);
if (!result.success) {
// logging, métricas, respuesta 400 al cliente...
throw new Error('Payload inválido');
}
const usuario = result.data;
safeParse devuelve un objeto con success y error para flujos menos crudos.
Dónde aplicar validación (regla práctica)
No todo necesita Zod. La regla del arquitecto es simple:
- Valida en runtime en las fronteras: entrada HTTP, webhooks, archivos subidos, variables de entorno, LocalStorage.
- Confía en TypeScript dentro del dominio: funciones internas, paso de props entre componentes, mutaciones internas en stores tipados.
Aplicar Zod en todas partes degrada rendimiento y readability. No validar en las fronteras te expone a fallos catastróficos.
Casos prácticos y patterns
1) Respuesta API (backend → frontend o backend → backend)
- Parsea siempre antes de usar.
- Registra el error y devuelve 400 o fallback claro.
2) Webhooks / n8n / automatizaciones
- Parsea y verifica firma si aplica.
- Rechaza rápido para evitar procesar datos corruptos.
3) Variables de entorno en arranque (ejemplo con Zod)
const EnvSchema = z.object({
DATABASE_URL: z.string().url(),
NODE_ENV: z.enum(['development','production']),
});
const env = EnvSchema.parse(process.env);
Arranque fallido = fallo visible y evitar estados inconsistentes.
4) Formularios en frontend
Integra Zod con React Hook Form para validar antes de mutar el estado o enviar al servidor.
Coste y alternativas: cuándo preocuparse por rendimiento
Zod añade CPU y peso al bundle. En la mayoría de apps esto es irrelevante frente a la estabilidad que gana tu producto. En sistemas de altísima demanda (millones de eventos por segundo) evalúa alternativas más ligeras o validaciones a medida.
Alternativas emergentes existen, pero la elección debe basarse en mediciones. No te cases con una librería sin perf tests en tu caso real.
Integración práctica: patrón recomendado
- Punto de entrada (API handler, webhook) → Zod parse
- Convertir a tipos con z.infer → pasar al core tipado con TypeScript
- Lógica interna → TypeScript puro, sin comprobaciones redundantes
- En el cliente, validar inputs críticos; en el servidor, validar todo lo externo
Conclusión y pasos accionables
- Zod y TypeScript no son excluyentes. TypeScript organiza tu código; Zod lo hace seguro en producción.
- Si tienes que elegir hoy, empieza por defender las fronteras: añade validación Zod en endpoints y webhooks.
- Usa
z.inferpara que el tipo estático derive del esquema y mide impacto.
Recuerda: el compilador no vive en producción. Tú sí. Protege lo que importa.
Prueba esto ahora: añade un esquema Zod a uno de tus endpoints y corre safeParse con un payload inesperado. Verás la diferencia. Esto no acaba aquí; la próxima nota tratará cómo estructurar esquemas Zod para versiones y migraciones sin romper consumidores.
FAQ
¿TypeScript protege mi app en producción?
No. TypeScript es un analizador estático y sus tipos desaparecen al compilar (type erasure). No impide que datos inválidos lleguen a runtime.
¿Qué es Zod y por qué usarlo?
Zod es una librería de validación y parsing en runtime. Su filosofía es “parse, don’t validate”: parsea datos y falla rápido si no coinciden con el esquema, evitando errores silenciosos en producción.
¿Cuándo usar parse vs safeParse?
Usa parse cuando quieras que el proceso lance inmediatamente y falle rápido. Usa safeParse para manejar errores de forma controlada (logging, métricas, respuesta 400) sin exceptions no controladas.
¿Dónde aplicar validación en mi arquitectura?
Valida en las fronteras: endpoints HTTP, webhooks (p. ej. n8n), archivos subidos, variables de entorno, y LocalStorage. Dentro del dominio confía en TypeScript y evita validaciones redundantes.
¿Zod impacta tanto el rendimiento?
Zod añade CPU y peso al bundle, pero en la mayoría de apps el coste es aceptable frente a la estabilidad que aporta. En sistemas de altísima demanda evalúa alternativas más ligeras y mide con perf tests.
¿Cómo integrar Zod con TypeScript sin duplicar tipos?
Define esquemas Zod y deriva los tipos estáticos con z.infer. Así mantienes una sola fuente de verdad: el esquema.
