Cómo manejar variables de entorno en Node.js con dotenv y process.env paso a paso
Introducción
En cualquier proyecto de Node.js es habitual encontrarse con valores que no deben quedar hardcodeados en el código fuente: credenciales de bases de datos, claves de APIs, puertos de escucha, etc. Estos valores se conocen como variables de entorno y su correcta gestión es fundamental para:
- Mantener la seguridad (evitar que secretos se publiquen en repositorios).
- Permitir que la misma aplicación se ejecute en distintos entornos (desarrollo, testing, producción) sin cambios en el código.
- Facilitar la configuración en contenedores y plataformas cloud.
Este artículo está dirigido a desarrolladores que ya manejan Node.js a nivel básico y quieren aprender a usar dotenv junto a process.env de forma práctica y segura. Al terminar, sabrás cómo crear, cargar y consumir variables de entorno, cómo definir valores por defecto, y qué errores comunes evitar.
1. ¿Qué son las variables de entorno?
Una variable de entorno es un par clave/valor que el sistema operativo pone a disposición de los procesos que se ejecutan. En Node.js, todas esas variables están accesibles a través del objeto global process.env.
console.log(process.env.PATH); // Imprime la variable PATH del sistemaEn la práctica, usamos variables de entorno para separar la configuración del código. Así, el mismo código puede correr en distintas máquinas simplemente cambiando el archivo de configuración.
2. Por qué usar dotenv
Node.js no tiene una forma nativa de leer archivos .env. La librería dotenv llena ese vacío: lee un archivo de texto plano con formato KEY=VALUE y carga esas parejas dentro de process.env antes de que tu aplicación arranque.
Ventajas principales:
- Simplicidad: sólo agregar una línea de código.
- Compatibilidad: funciona con cualquier versión de Node.
- Flexibilidad: puedes tener varios archivos
.env(por ejemplo,.env.development,.env.test).
3. Instalación y configuración básica
3.1 Instalar la dependencia
npm install dotenv --save3.2 Crear el archivo .env
En la raíz del proyecto, crea un archivo llamado .env y agrega tus variables:
# .env
PORT=3000
DB_HOST=localhost
DB_USER=admin
DB_PASS=supersecret
API_KEY=abcdef123456Nota: el archivo no debe subirse al control de versiones. Añádelo a
.gitignore.
echo '.env' >> .gitignore3.3 Cargar el archivo al iniciar la app
En el punto de entrada de tu aplicación (por lo general index.js o app.js) agrega la siguiente línea antes de cualquier otro require que dependa de variables de entorno:
require('dotenv').config();
console.log('Variables cargadas:', process.env.PORT, process.env.DB_HOST);Salida esperada (asumiendo que el archivo .env contiene los valores mostrados antes):
Variables cargadas: 3000 localhost4. Accediendo a variables de entorno en tu código
Una vez que dotenv ha ejecutado config(), todas las variables estarán disponibles en process.env. Veamos algunos casos de uso.
4.1 Configuración de un servidor Express
require('dotenv').config();
const express = require('express');
const app = express();
const PORT = process.env.PORT || 8080; // valor por defecto si no está definido
app.get('/', (req, res) => {
res.send('Hola Mundo!');
});
app.listen(PORT, () => {
console.log(`Servidor escuchando en http://localhost:${PORT}`);
});Salida esperada (con el .env anterior):
Servidor escuchando en http://localhost:3000Si eliminamos PORT del archivo .env, la salida será http://localhost:8080 gracias al valor por defecto.
4.2 Conexión a una base de datos con pg (PostgreSQL)
require('dotenv').config();
const { Client } = require('pg');
const client = new Client({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: 'mydb'
});
client.connect()
.then(() => console.log('Conectado a PostgreSQL'))
.catch(err => console.error('Error de conexión:', err.message));Salida esperada (asumiendo credenciales correctas):
Conectado a PostgreSQLImportante: nunca imprimas directamente una variable sensible (como
DB_PASS) en logs de producción.
5. Variables de entorno por entorno (development, test, production)
En proyectos reales, cada entorno tiene su propio conjunto de valores. dotenv permite cargar archivos diferentes según una variable NODE_ENV.
5.1 Estructura de archivos
my-app/
├─ .env.development
├─ .env.test
├─ .env.production
├─ index.js5.2 Código para seleccionar el archivo correcto
const env = process.env.NODE_ENV || 'development';
require('dotenv').config({ path: `.env.${env}` });
console.log('Entorno:', env);
console.log('Puerto configurado:', process.env.PORT);Supongamos que los archivos contienen:
.env.development→PORT=3001.env.test→PORT=4000.env.production→PORT=80
Ejemplo de ejecución
NODE_ENV=development node index.jsSalida:
Entorno: development
Puerto configurado: 3001NODE_ENV=production node index.jsSalida:
Entorno: production
Puerto configurado: 806. Buenas prácticas y errores comunes
6.1 Buenas prácticas
- Mantener
.envfuera del VCS- Añadí siempre a
.gitignore.
- Añadí siempre a
- Usar valores por defecto en el código
const PORT = process.env.PORT || 3000;
- Validar variables al iniciar
- Usa librerías como
joiozodpara chequear que todas las variables necesarias están presentes.
- Usa librerías como
- No almacenar secretos en logs
- Evita
console.log(process.env)en producción.
- Evita
- Documentar variables esperadas
- Crea un
README-ENV.mdcon descripción y ejemplos.
- Crea un
6.2 Errores comunes
| Error | Por qué ocurre | Cómo evitarlo |
|---|---|---|
Olvidar require('dotenv').config() antes de usar process.env |
Las variables aún no están cargadas | Colocá la línea como la primera instrucción de tu entry point |
Tener espacios o comillas en el archivo .env |
dotenv interpreta todo como parte del valor |
Usa KEY=value sin comillas y sin espacios alrededor del = |
Subir el .env al repo |
Exposición de credenciales | Añadí .env* al .gitignore y usa git rm --cached .env si ya está versionado |
| Usar variables que no existen y no definir un fallback | La aplicación falla con undefined |
Siempre proveé un valor por defecto o lanza un error explícito |
Cargar varios archivos .env sin control |
Sobrescritura inesperada de valores | Usa la opción override: false o carga manualmente según la lógica de tu app |
7. Herramientas complementarias
- dotenv-cli: permite ejecutar scripts con variables de un archivo
.envsin modificar tu código. - cross-env: útil para definir variables de entorno en scripts npm de forma portable (Windows/Linux).
- dotenv-safe: verifica que todas las variables requeridas estén definidas y opcionalmente usa un archivo
.env.examplecomo plantilla.
7.1 Ejemplo con dotenv-safe
- Instalar:
npm install dotenv-safe --save- Crear
.env.examplecon las claves obligatorias:
# .env.example
PORT=
DB_HOST=
DB_USER=
DB_PASS=- En tu entry point:
require('dotenv-safe').config();
console.log('Todas las variables obligatorias están presentes');Si falta alguna variable, la ejecución aborta con un mensaje claro.
8. Uso de variables de entorno en Docker y CI/CD
Cuando desplegás en contenedores, no usás archivos .env dentro de la imagen. En su lugar, pasás variables al docker run o al docker-compose.yml.
# docker-compose.yml
version: '3.8'
services:
app:
image: my-node-app
env_file:
- .env.production
ports:
- "80:3000"En pipelines de GitHub Actions, definís secretos y los exponés como variables:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install deps
run: npm ci
- name: Run tests
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
run: npm test9. Resumen de comandos útiles
# Instalar dotenv
npm install dotenv --save
# Añadir .env al .gitignore
echo '.env' >> .gitignore
# Ejecutar con variable de entorno específica
NODE_ENV=production node index.js
# Usar dotenv-cli para correr sin modificar código
npx dotenv -e .env.production -- node index.jsConclusión
Manejar variables de entorno en Node.js con dotenv y process.env es una práctica esencial para escribir aplicaciones seguras, configurables y portables. Aprendimos a:
- Crear y cargar un archivo
.env. - Acceder a los valores mediante
process.envcon fallback seguros. - Gestionar distintos entornos (development, test, production).
- Aplicar buenas prácticas y evitar errores típicos.
- Integrar la configuración con Docker y pipelines CI/CD.
Con estos conceptos, ya podés estructurar tu proyecto de manera que la configuración quede separada del código, lo que facilita el mantenimiento y la escalabilidad. Como próximo paso, considerá usar dotenv-safe o esquemas de validación con zod para reforzar la robustez de tu configuración.
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.