DevToolBoxGRATIS
Blog

Guía de archivos .env: Mejores prácticas de variables de entorno

10 min de lecturapor DevToolBox

Las variables de entorno mantienen los secretos fuera del código fuente y permiten cambiar la configuración sin redesplegar. El archivo .env se ha convertido en la forma estándar de gestionarlas localmente. Esta guía cubre reglas de sintaxis, configuración de frameworks, seguridad, archivos específicos por entorno, integración con Docker, errores comunes y alternativas en producción.

Reglas de sintaxis .env

Un archivo .env es un archivo de texto plano con una variable por línea. Estas son las reglas que todo desarrollador debe conocer:

Sintaxis básica

Cada línea sigue el patrón KEY=VALUE. Sin espacios alrededor del signo igual.

# .env
DATABASE_URL=postgres://localhost:5432/mydb
API_KEY=sk-1234567890abcdef
PORT=3000
DEBUG=true

Reglas de comillas

Los valores pueden ir sin comillas, con comillas simples o dobles. El comportamiento difiere:

# Unquoted — trailing whitespace trimmed
APP_NAME=My Application

# Single quotes — literal, no interpolation
PASSWORD='p@$$w0rd#123'

# Double quotes — escape sequences + interpolation
GREETING="Hello\nWorld"
FULL_URL="${BASE_URL}/api/v1"
  • Sin comillas: se eliminan espacios finales, sin secuencias de escape.
  • Comillas simples: el valor se toma literalmente, sin interpolación ni escape.
  • Comillas dobles: soporta secuencias de escape (\n, \t) e interpolación de variables.

Valores multilínea

Use comillas dobles y \n para saltos de línea, o saltos de línea reales dentro de comillas dobles:

# Method 1: \n in double quotes
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIB...\n-----END RSA PRIVATE KEY-----"

# Method 2: actual newlines in double quotes
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----"

Comentarios

Las líneas que comienzan con # son comentarios. Los comentarios en línea funcionan solo con valores sin comillas en algunos parsers:

# This is a full-line comment
DATABASE_URL=postgres://localhost/mydb  # inline comment (some parsers)

# Empty lines are ignored

API_KEY=abc123  # This may or may not work depending on the parser

Interpolación de variables

Referencia otras variables usando la sintaxis ${VAR} (soportado por la mayoría de parsers en valores con comillas dobles):

BASE_URL=https://api.example.com
API_V1=${BASE_URL}/v1
API_V2=${BASE_URL}/v2

DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DATABASE_URL=postgres://${DB_HOST}:${DB_PORT}/${DB_NAME}

Configuración de frameworks

Node.js (dotenv)

El cargador .env más popular para Node.js. Instalación y configuración:

# Install
npm install dotenv

# --- app.js (CommonJS) ---
require('dotenv').config();
console.log(process.env.DATABASE_URL);

# --- app.ts (ES Modules) ---
import 'dotenv/config';
console.log(process.env.DATABASE_URL);

# --- Or load from CLI ---
node -r dotenv/config app.js
node -r dotenv/config app.js dotenv_config_path=.env.local

Next.js, Vite y Create React App cargan archivos .env automáticamente — no se necesita paquete.

Python (python-dotenv)

Cargar .env en proyectos Python:

# Install
pip install python-dotenv

# --- app.py ---
from dotenv import load_dotenv
import os

load_dotenv()  # loads .env from current directory
# load_dotenv('.env.local')  # or specify a path

database_url = os.getenv('DATABASE_URL')
print(database_url)

# --- Django: manage.py or settings.py ---
from dotenv import load_dotenv
from pathlib import Path

env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

Go (godotenv)

Cargar .env en proyectos Go:

// Install
// go get github.com/joho/godotenv

package main

import (
    "fmt"
    "log"
    "os"
    "github.com/joho/godotenv"
)

func main() {
    err := godotenv.Load()  // loads .env
    if err != nil {
        log.Fatal("Error loading .env file")
    }
    dbURL := os.Getenv("DATABASE_URL")
    fmt.Println(dbURL)
}

PHP (vlucas/phpdotenv)

Usado por Laravel y la mayoría de frameworks PHP:

// Install
// composer require vlucas/phpdotenv

<?php
require 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

// Access variables
$dbUrl = $_ENV['DATABASE_URL'];
// or
$dbUrl = getenv('DATABASE_URL');

// Required variables (throws exception if missing)
$dotenv->required(['DATABASE_URL', 'API_KEY']);

Ruby (gem dotenv)

Usado por Rails y otros proyectos Ruby:

# Gemfile
gem 'dotenv-rails', groups: [:development, :test]

# Or for non-Rails Ruby:
gem 'dotenv'

# --- app.rb ---
require 'dotenv/load'
puts ENV['DATABASE_URL']

# --- Rails: .env is loaded automatically ---
# Access via ENV['DATABASE_URL'] anywhere in your app

Seguridad: nunca hagas commit de archivos .env

Tu archivo .env contiene secretos (claves API, contraseñas de base de datos, tokens). Hacer commit al control de versiones es el error de seguridad n.°1.

Patrones .gitignore

Agrega estos patrones a tu archivo .gitignore inmediatamente:

# .gitignore

# Ignore all .env files
.env
.env.local
.env.*.local
.env.development
.env.production

# More aggressive pattern — ignore all .env variants
.env*

# But DO commit the example file
!.env.example

Usar .env.example

Haz commit de un archivo .env.example con valores vacíos para que los compañeros sepan qué variables se necesitan:

# .env.example — commit this file
# Copy to .env and fill in your values

DATABASE_URL=
API_KEY=
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
REDIS_URL=
JWT_SECRET=

# Optional
DEBUG=false
LOG_LEVEL=info

¿Ya hiciste commit del .env?

Si accidentalmente hiciste commit de un archivo .env, elimínalo del seguimiento y rota todos los secretos:

# Step 1: Remove .env from Git tracking (keeps local file)
git rm --cached .env

# Step 2: Add to .gitignore
echo ".env" >> .gitignore

# Step 3: Commit the removal
git add .gitignore
git commit -m "Remove .env from tracking, add to .gitignore"

# Step 4: CRITICAL — Rotate ALL secrets in the .env file
# Every API key, password, and token that was exposed
# must be regenerated immediately

Archivos específicos por entorno

La mayoría de frameworks soportan múltiples archivos .env para diferentes entornos. Entender el orden de carga es crítico.

Orden de carga (Next.js / Vite / CRA)

Los archivos se cargan en esta prioridad (los archivos posteriores sobrescriben a los anteriores):

# Loading priority (highest to lowest):

# 1. Shell environment variables (always win)
# 2. .env.{NODE_ENV}.local   (e.g. .env.production.local)
# 3. .env.local               (NOT loaded in test)
# 4. .env.{NODE_ENV}          (e.g. .env.production)
# 5. .env                     (default fallback)

# Example for NODE_ENV=production:
# .env                     → loaded first (base defaults)
# .env.production          → overrides .env
# .env.local               → overrides .env.production
# .env.production.local    → overrides everything above

.env.local siempre es ignorado por git (agrégalo a .gitignore). NO se carga durante las pruebas para mantener los tests deterministas.

¿Qué archivo para qué?

FilePurposeGit
.envDefault values, non-secret configCommit
.env.exampleTemplate with empty valuesCommit
.env.localLocal secrets & overridesIgnore
.env.developmentDev-specific (shared)Commit
.env.productionProduction-specific (non-secret)Commit
.env.testTest environment configCommit
.env.production.localProduction secrets (local only)Ignore

Integración con Docker y Docker Compose

Directiva env_file

Docker Compose puede cargar archivos .env directamente en contenedores:

# docker-compose.yml (or compose.yml)
services:
  web:
    image: node:20-alpine
    env_file:
      - .env                  # base defaults
      - .env.production       # production overrides
    ports:
      - "3000:3000"

  db:
    image: postgres:16
    env_file:
      - .env.db               # separate file for DB secrets
    volumes:
      - pgdata:/var/lib/postgresql/data

environment vs env_file

También puedes definir variables de entorno en línea. Esta es la diferencia:

# Using env_file (loads from file)
services:
  web:
    env_file:
      - .env

# Using environment (inline)
services:
  web:
    environment:
      - NODE_ENV=production
      - PORT=3000
      - DATABASE_URL=${DATABASE_URL}   # from shell or .env

# Using environment (mapping syntax)
services:
  web:
    environment:
      NODE_ENV: production
      PORT: 3000
  • env_file: carga desde archivo, mantiene compose.yml limpio, fácil de cambiar por entorno.
  • environment: visible en compose.yml, bueno para valores no secretos, soporta sustitución de variables.

.env para variables de Docker Compose

Docker Compose lee automáticamente un archivo .env en la raíz del proyecto para sustitución de variables en compose.yml:

# .env (in same directory as compose.yml)
POSTGRES_VERSION=16
NODE_VERSION=20
APP_PORT=3000

# compose.yml — uses .env for variable substitution
services:
  web:
    image: node:${NODE_VERSION}-alpine
    ports:
      - "${APP_PORT}:3000"

  db:
    image: postgres:${POSTGRES_VERSION}
    environment:
      POSTGRES_DB: myapp

10 errores comunes de .env y soluciones

Estos son los problemas .env más frecuentes que encuentran los desarrolladores:

#ErrorCausaSolución
1process.env.VAR es undefineddotenv no cargado o cargado después del usoLlama a dotenv.config() al inicio del archivo de entrada
2Variables vacías en producciónArchivo .env no desplegado; dependencia del archivo en vez de variables de plataformaConfigura variables de entorno en tu plataforma de hosting (Vercel, AWS, etc.)
3Valores .env contienen comillasEl parser trata las comillas como caracteres literalesRevisa la documentación del parser
4Archivo .env incorrecto cargadoEl directorio de trabajo difiere de la ruta esperadaUsa la opción path: dotenv.config({ path: ".env.local" })
5Valor multilínea truncadoValor no correctamente entre comillas doblesEnvuelve valores multilínea en comillas dobles
6Caracteres especiales rompen el valor$ o # interpretado como interpolación/comentarioUsa comillas simples para prevenir interpolación, o escapa con \
7Error de codificación BOMEditor de Windows guarda .env con UTF-8 BOMGuarda como UTF-8 sin BOM
8Variables de entorno del contenedor Docker vacíasRuta de env_file incorrecta o archivo fuera del contexto de buildVerifica que la ruta sea relativa a la ubicación de compose.yml
9Espacios alrededor de = rompen el parsingKEY = VALUE en vez de KEY=VALUEElimina espacios alrededor del signo igual
10Variables no disponibles en el navegador (React/Next)Falta el prefijo requerido (NEXT_PUBLIC_ o REACT_APP_)Agrega el prefijo requerido por el framework para exponer al código del cliente

Alternativas en producción

En producción, los archivos .env no son recomendados. Usa estas alternativas:

Variables de entorno de plataforma

Cada plataforma de hosting importante proporciona UI o CLI para configurar variables de entorno:

# Vercel
vercel env add DATABASE_URL production
vercel env ls

# AWS (Parameter Store)
aws ssm put-parameter \
  --name "/myapp/prod/DATABASE_URL" \
  --value "postgres://..." \
  --type SecureString

# Heroku
heroku config:set DATABASE_URL=postgres://...
heroku config

# Railway
railway variables set DATABASE_URL=postgres://...

# Fly.io
fly secrets set DATABASE_URL=postgres://...

Docker Secrets

Para Docker Swarm o Compose, usa secrets para datos sensibles:

# compose.yml with Docker secrets
services:
  web:
    image: myapp:latest
    secrets:
      - db_password
      - api_key
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt    # for Compose
    # external: true                    # for Swarm
  api_key:
    file: ./secrets/api_key.txt

# In your app, read from file:
# const secret = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();

Gestores de secretos (Vault, AWS Secrets Manager)

Para aplicaciones empresariales, usa un gestor de secretos dedicado:

# HashiCorp Vault
vault kv put secret/myapp/production \
  DATABASE_URL="postgres://..." \
  API_KEY="sk-..."

# Read in application
vault kv get -field=DATABASE_URL secret/myapp/production

# AWS Secrets Manager
aws secretsmanager create-secret \
  --name "myapp/production/db" \
  --secret-string '{"url":"postgres://...","password":"..."}'

# Read in Node.js with AWS SDK
import { SecretsManager } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManager({ region: 'us-east-1' });
const { SecretString } = await client.getSecretValue({
  SecretId: 'myapp/production/db'
});
const secrets = JSON.parse(SecretString);

Los gestores de secretos proporcionan rotación, logs de auditoría, control de acceso y cifrado en reposo — funciones que los archivos .env no pueden ofrecer.

Preguntas frecuentes

¿Debo hacer commit de mi archivo .env en Git?

Nunca hagas commit de archivos .env con secretos al control de versiones. En su lugar, haz commit de un archivo .env.example con valores vacíos. Agrega patrones .env* a tu .gitignore.

¿Cuál es la diferencia entre .env, .env.local y .env.production?

.env contiene valores por defecto cargados en todos los entornos. .env.local contiene sobrecargas locales no committeadas. .env.production contiene valores específicos de producción cargados solo cuando NODE_ENV=production.

¿Por qué process.env.MY_VAR es undefined en Node.js?

Causas más comunes: 1) Olvidar llamar require("dotenv").config() al inicio, 2) El archivo .env no está en la raíz, 3) Error tipográfico en el nombre de variable, 4) Con ES modules, usar "import dotenv/config".

¿Cómo uso variables .env en Docker Compose?

Docker Compose lee automáticamente un archivo .env en el mismo directorio que compose.yml para sustitución de variables ${VAR}. Usa env_file o environment para pasar variables a contenedores.

¿Se pueden usar archivos .env en producción?

No es recomendado. En producción, usa variables de entorno de plataforma, Docker secrets o un gestor de secretos como HashiCorp Vault o AWS Secrets Manager.

¿Cómo expongo variables .env al navegador en React o Next.js?

En Next.js, prefija con NEXT_PUBLIC_. En Create React App, usa REACT_APP_. En Vite, usa VITE_. Solo las variables con prefijo se incluyen en el bundle del cliente.

𝕏 Twitterin LinkedIn
¿Fue útil?

Mantente actualizado

Recibe consejos de desarrollo y nuevas herramientas.

Sin spam. Cancela cuando quieras.

Prueba estas herramientas relacionadas

🐳Docker Compose Generator.gi.gitignore GeneratorNXNginx Config Generator

Artículos relacionados

Hoja de referencia Docker Compose: Servicios, volúmenes y redes

Referencia Docker Compose: definiciones de servicios, volúmenes, redes, variables de entorno y ejemplos de stacks.

Docker Compose env_file vs environment: Cuándo usar cuál (con ejemplos)

Entiende la diferencia entre env_file y environment en Docker Compose. Casos de uso, prioridad de variables y configuraciones multi-entorno.