Zod valida process.env al iniciar Node.js para que las implementaciones mal configuradas fallen antes de aceptar tráfico. Un esquema te proporciona comprobaciones en tiempo de ejecución y tipos de TypeScript sin desviaciones.
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
import { z } from "zod";const envSchema = z.object({ NODE_ENV: z.enum(["development", "test", "production"]), PORT: z.coerce.number().int().min(1).max(65535).default(3000), DATABASE_URL: z.string().url(), JWT_SECRET: z.string().min(32),});export type Env = z.infer<typeof envSchema>;export const env = envSchema.parse(process.env);
# CI: valida el archivo .env de ejemplonpx tsx -e "import { envSchema } from './src/env'; envSchema.parse(require('dotenv').config({path:'.env.example'}).parsed)"
Cuándo usarlo:
Cualquier servicio con más de 3 variables de entorno
Comprobaciones de paridad de entorno de staging/producción en CI
Prevención de URLs de base de datos undefined en tiempo de ejecución
Equipos que incorporan nuevos ingenieros que copian .env.example
El paquete env-schema se integra con Fastify y JSON Schema. Zod es más común en bases de código Express/Nest que priorizan TypeScript y se compone con esquemas de cuerpo de solicitud.
// Pasa Env a las fábricas - nunca pases todo process.envexport function createDbPool(cfg: Pick<Env, "DATABASE_URL">) { return new Pool({ connectionString: cfg.DATABASE_URL });}
Analizar el entorno en cada importación de archivo de prueba - El orden importa si env.ts sale por variables faltantes. Solución:loadEnv(testEnv) con un ayudante reset o vi.stubEnv.
Valores predeterminados que ocultan secretos de producción faltantes - .default("changeme") en JWT_SECRET. Solución: No hay valores predeterminados en los secretos; falla si están ausentes en producción.
Registrar el entorno analizado - console.log(env) filtra secretos. Solución: Registra solo las claves o usa un serializador redactado.
Esquemas enormes en un solo archivo - 40 variables se vuelven inmanejables. Solución: Divide por dominio (dbEnv, authEnv) y fusiona con .merge().
Omitir la validación de .env.example en CI - El archivo de ejemplo se desvía del esquema. Solución: El trabajo de CI analiza .env.example a través del esquema.
Usa safeParse en la entrada de la aplicación cuando quieras registros formateados antes de salir. Cualquiera de los dos está bien si un manejador global formatea ZodError.
¿Cómo pruebo el código que importa el entorno?
Pasa un objeto de prueba a loadEnv({ DATABASE_URL: "postgres://..." }) y restablece la configuración en caché entre pruebas.
¿Funciona Zod con NestJS ConfigModule?
Sí. Valida process.env en ConfigModule.forRoot({ validate }) usando el mismo esquema Zod.
¿Cómo valido campos opcionales solo para producción?
Usa .refine en NODE_ENV === "production" o uniones discriminadas en NODE_ENV.
¿Puedo generar .env.example desde Zod?
No está integrado. Mantén .env.example manualmente o crea un script a partir de los metadatos del esquema que añades como .describe().
¿Qué pasa con los secretos en los mensajes de error de Zod?
Zod no repite los valores por defecto en los problemas. Evita imprimir result.error.flatten().fieldErrors junto con volcados brutos de process.env.
¿Debería staging usar el mismo esquema que producción?
Mismo esquema, diferentes valores. Los campos opcionales pueden diferir si .refine codifica reglas específicas del entorno.
¿Cómo manejo las claves PEM multilínea?
Codifica en Base64 en el entorno o usa el montaje de archivos del gestor de secretos; Zod valida la presencia y la longitud mínima, no el formato de los saltos de línea.
¿Es z.coerce.boolean() seguro para el entorno?
Boolean("false") es true en JavaScript. Prefiere z.enum(["true","false"]).transform(v => v === "true").
¿Cuándo debo cambiar a gestores de secretos?
Cuando las claves rotan semanalmente o el cumplimiento prohíbe las variables de entorno en los manifiestos de k8s. Zod sigue validando los valores resueltos después de la obtención.