Valida las variables de entorno de Node.js con Zod y TypeScript
Deja de leer process.env en todo el código de Node.js. Un archivo env.ts validado con Zod detecta los secretos faltantes al iniciar y proporciona a la aplicación una configuración de TypeScript tipada.
Imagínese una implementación el viernes por la tarde. La compilación tiene éxito, el servidor arranca y todos se van a casa. Una hora después, los usuarios informan que los inicios de sesión fallan. Resulta que nadie estableció el valor de JWT_SECRET en el entorno de producción. La aplicación funcionó bien al principio y solo falló cuando la primera solicitud accedió al código que necesitaba ese valor faltante.
Consultar constantemente process.env en todo el código hace que este tipo de incidentes sean probables. A continuación se muestra cómo reemplazar esa práctica por un módulo de configuración validado y con tipos definidos, utilizando Zod y TypeScript.
El enfoque habitual
La mayoría del código de Node.js obtiene la configuración justo donde se necesita: un puerto en un archivo, una cadena de conexión a la base de datos en otro.
// Some random controller file
const port = process.env.PORT || 3000;
mongoose.connect(process.env.MONGO_URI);
Es práctico, pero tiene tres problemas reales.
- Falta de seguridad en los tipos. En TypeScript,
process.env.PORTes de tipostring | undefined. Si se necesita un número, cada lugar donde se utilice debe parsearlo manualmente. - Fallas silenciosas. Cuando
MONGO_URIno está definido, el proceso no se cae al iniciar. Sí se cae cuando finalmente se ejecuta esa línea, posiblemente horas después de un despliegue que parecía correcto. - Falta de una única fuente de verdad. Un recién llegado no cuenta con una lista de las variables que necesita la aplicación. Su única opción es buscar en todo el repositorio la referencia a
process.env.
Un único archivo de control
La solución es dejar de modificar process.env en la lógica de negocio. Un único módulo, llamémoslo env.ts, lee el entorno una sola vez al iniciar, lo valida y exporta un objeto de tipo estricto. Todo lo demás importa ese objeto.
Zod, una biblioteca de validación de esquemas orientada a TypeScript, se encarga de la validación.
Instálala
npm install zod
Escribe el esquema
Coloca el módulo en src/config/env.ts y describe con exactitud cómo debe ser el entorno.
import dotenv from 'dotenv';
import { z } from 'zod';
// Load variables from .env file (if in development)
dotenv.config();
// 1. Define the schema
const envSchema = z.object({
PORT: z.string().transform(Number).default('3000'),
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
MONGO_URI: z.string(),
JWT_SECRET: z.string(),
JWT_EXPIRES_IN: z.string().default('1d'),
});
// 2. Parse the environment against the schema
const _env = envSchema.safeParse(process.env);
// 3. Fail fast if it's invalid
if (!_env.success) {
console.error('Invalid environment variables:', _env.error.format());
process.exit(1); // Crash the app immediately!
}
// 4. Export the typed, validated object
export const env = _env.data;
Qué hace el módulo
- Declara las expectativas.
MONGO_URIes una cadena obligatoria.PORTse proporciona como cadena, y.transform(Number)la convierte, con un valor por defecto de 3000.NODE_ENVdebe ser uno de los tres valores permitidos. - Genera un error de inmediato.
safeParsese ejecuta en el momento en que se importa el archivo, por lo que hay que importarlo en la parte superior de su punto de entrada, ya seaapp.tsoserver.ts. Si falta o está mal formada alguna variable obligatoria, el resultado indica un fallo, la salida de error indica con precisión qué salió mal yprocess.exit(1)detiene el proceso antes de que sirva tráfico. - Exporta un objeto tipado. En caso de éxito, los datos analizados incluyen los tipos inferidos por Zod, de modo que
env.PORTya es un número.
A partir de entonces, cualquier archivo puede importar env y utilizarlo.
Qué obtienes
- Autocompletado. Al escribir
env.en tu editor, se muestran todas las variables disponibles. - Sin soluciones alternativas dispersas. Los patrones
|| "default_value"desaparecen de los controladores, ya que los valores por defecto se encuentran en el esquema. - Documentación integrada. El esquema es una lista precisa de lo que necesita la aplicación para funcionar, lo que también responde a las dudas de los recién llegados sobre qué debe incluirse en
.env.
Un valor secreto faltante ahora impide el despliegue en cuestión de segundos, al iniciar la aplicación, con un mensaje claro, en lugar de que un usuario molesto lo descubra una hora después.
Leer más
- Un pipeline RAG en 90 líneas de Python: recuperación, enriquecimiento y generación — Construye desde cero un sistema de generación enriquecida mediante recuperación de información usando embeddings, similitud coseno y una lista ordenada, y observa dónde falla la versión simplificada a escala mayor.
- Ejecuta Qwen3.8-Flash-Next localmente como agente de programación con llama.cpp y OpenCode — Guía paso a paso para ejecutar un modelo de programación de 125B MoE en tu propia GPU con llama.cpp, ofrecerlo a través de una API al estilo de OpenAI y controlarlo desde OpenCode.