← Node & Express

Fundamentos de Node

¿Qué son las variables de entorno en Node.js, cómo las lees, y por qué no debes hardcodear secretos en el código?

Ver respuesta — intenta responderla en voz alta primero

Las variables de entorno son valores de configuración que viven fuera del código, en el entorno donde corre la aplicación. En Node se leen con process.env. En desarrollo se suelen guardar en un archivo .env cargado con la librería dotenv. No se deben hardcodear secretos (contraseñas, API keys) en el código porque terminan en el control de versiones, quedan expuestos y son difíciles de cambiar entre entornos.

Una aplicación necesita configuración que cambia según dónde corre: el puerto, la URL de la base de datos, las llaves de servicios externos. Esa configuración no debe estar escrita en el código, porque:

  • Cambia entre entornos (desarrollo, pruebas, producción).
  • Algunos valores son secretos (contraseñas, tokens) y no deben quedar en el repositorio.

La solución son las variables de entorno: valores que el sistema operativo (o la plataforma de despliegue) le pasa a tu proceso. En Node las lees a través del objeto process.env, que es un objeto con todas las variables disponibles.

El archivo .env y dotenv: en desarrollo es incómodo escribir las variables a mano en la terminal cada vez. Por eso se usa un archivo llamado .env con pares CLAVE=valor, y la librería dotenv, que lee ese archivo y mete sus valores en process.env. Muy importante: el archivo .env debe estar en .gitignore para que nunca se suba al repositorio.

Por qué NO hardcodear secretos:

  • Si escribes una contraseña o API key directamente en el código, queda en el historial de Git para siempre, aunque después la borres.
  • Cualquiera con acceso al repositorio (o si el repo se filtra) ve tus credenciales.
  • No puedes usar valores distintos por entorno sin editar el código.
  • Rotar (cambiar) un secreto obliga a modificar y desplegar código.

Buenas prácticas:

  • Todos los secretos y configuración van en variables de entorno.
  • Usa siempre un valor por defecto razonable donde tenga sentido (por ejemplo el puerto), para que la app arranque igual en local.
  • Sube al repo un archivo de ejemplo .env.example (sin valores reales) que documente qué variables se necesitan.
  • Recuerda que todo en process.env es texto (string): si necesitas un número, conviértelo con Number().
// Cargar las variables del archivo .env dentro de process.env.
// (Debe ir lo mas arriba posible, antes de usar las variables.)
require("dotenv").config();

// Leer el puerto con un valor por defecto: si PORT no esta definido, usa 3000.
const PORT = process.env.PORT || 3000;

// Un secreto: NUNCA se escribe aqui directamente, se lee del entorno.
const API_KEY = process.env.API_KEY;

if (!API_KEY) {
  // Fallar temprano y claro si falta una variable critica.
  throw new Error("Falta la variable de entorno API_KEY");
}

// process.env siempre da strings; si necesitas numero, conviertelo:
const MAX_CONEXIONES = Number(process.env.MAX_CONEXIONES) || 10;

console.log(`Servidor arrancara en el puerto ${PORT}`);
console.log(`Maximo de conexiones: ${MAX_CONEXIONES}`);
# archivo: .env  (este archivo va en .gitignore, NUNCA se sube)
PORT=8080
API_KEY=sk_live_ejemplo_no_real_123
MAX_CONEXIONES=25
# archivo: .env.example  (este SI se sube, sin valores reales)
PORT=
API_KEY=
MAX_CONEXIONES=

Nota: a partir de Node.js 20 existe la bandera node --env-file=.env app.js, que carga un archivo .env sin necesidad de la librería dotenv. Aun así, dotenv sigue siendo la opción más común y compatible.

Escribir el secreto directo en el código "solo por ahora" (const API_KEY = "sk_live_abc123") y subirlo al repositorio. Aunque después lo borres, queda en el historial de Git y debe considerarse comprometido: hay que rotar (cambiar) esa credencial. Otro error frecuente es olvidar poner .env en el .gitignore, con lo que el archivo con los secretos termina publicado.

"Las variables de entorno son la configuración que vive fuera del código, en el entorno donde corre la app, y en Node las leo con process.env. En desarrollo las guardo en un archivo .env que cargo con dotenv, y ese archivo lo pongo en gitignore para que nunca llegue al repo. No hardcodeo secretos porque quedarían en el historial de Git para siempre, expuestos, y sería un lío cambiarlos entre entornos. Siempre uso valores por defecto donde tiene sentido, por ejemplo process.env.PORT con un fallback a 3000, valido temprano las variables críticas, y recuerdo que todo en process.env es string, así que convierto a número cuando hace falta."

Reto rápido

¿Qué imprime este código si la variable de entorno PORT no está definida?

const PORT = process.env.PORT || 3000;
console.log(typeof PORT, PORT);

Y si en cambio ejecutas con PORT=8080 node app.js, ¿qué imprime?

Ver respuesta

Sin PORT definido imprime: number 3000. Como process.env.PORT es undefined, el operador || usa el valor por defecto 3000, que es un número literal.

Con PORT=8080 node app.js imprime: string 8080. Ahora process.env.PORT sí existe, pero como todo en process.env es texto, su tipo es string, no number. Por eso, si vas a hacer operaciones numéricas, conviene convertirlo con Number(process.env.PORT).