Ir al contenido

El medio de los artesanos de la web domingo, 13 de septiembre de 2026

MailStudio
Herramientas

Variables de entorno y secretos: gestionarlos bien en desarrollo web

Sacar la configuración del código no es una manía de orden: es la frontera entre un secreto protegido y una clave de API publicada por error. Repaso de las prácticas que aguantan con el tiempo, del archivo .env a los gestores de…

Illustration : variables d'environnement et secrets

Una clave de API subida sin querer a un repositorio público, una contraseña de base de datos fijada en el código, una variable «pública» que acaba en el bundle de JavaScript entregado al navegador: la mayoría de las fugas de secretos no vienen de un ataque sofisticado, sino de una configuración mal ordenada. Separar la configuración del código sigue siendo uno de los gestos más rentables del desarrollo web, y uno de los peor dotados de herramientas en los proyectos que crecen deprisa.

Por qué la configuración va fuera del código

El principio es antiguo y cabe en una frase: el código describe qué hace la aplicación, la configuración describe dónde y cómo se ejecuta. Una misma base de código debe arrancar en local, en preproducción y en producción sin que cambie una sola línea; solo difieren los valores del entorno. Es la recomendación formalizada por la metodología Twelve-Factor App, y tiene una consecuencia directa en seguridad: lo que vive en el entorno no vive en el historial de Git.

La distinción útil no es «secreto» frente a «no secreto», sino «lo que cambia según el entorno». La URL de una API de preproducción no es confidencial, pero pertenece a la configuración igual que un token de acceso. Endurecer un servidor empieza por el mismo reflejo: ninguna credencial en claro dentro de un archivo versionado.

El archivo .env y la regla del .gitignore

La convención dominante es un archivo .env en la raíz del proyecto: una lista de pares CLAVE=valor, uno por línea. Su fuerza es la simplicidad; su trampa es que resulta trivial subirlo por accidente. La primera línea que escribir en un proyecto no es una variable, es la exclusión del archivo:

# .gitignore — à faire AVANT le premier commit
.env
.env.*
!.env.example

El archivo realmente versionado es un .env.example que documenta las claves esperadas sin sus valores. Un nuevo integrante del equipo lo copia a .env y lo rellena. Una versión típica se ve así:

# .env.example — versionné, sans secrets
APP_ENV=local
APP_DEBUG=true
DATABASE_URL=
STRIPE_SECRET_KEY=
MAIL_DSN=

El prefijo que expone al navegador. Las herramientas de build de front (Vite, Next.js) inyectan en el código cliente solo las variables con un prefijo acordado: VITE_ para Vite, NEXT_PUBLIC_ para Next.js. Todo lo que lleve ese prefijo es público: acaba legible en el bundle que descarga cada visitante. Una clave secreta nunca debe llevar ese prefijo, so pena de servirse al mundo entero.

Cargar las variables según el stack

Cada ecosistema tiene su forma de leer el entorno. Los tres más habituales en la web se parecen en la intención pero difieren en los detalles.

En PHP, Laravel lee el .env automáticamente al arrancar y expone los valores mediante la ayuda env(). Un punto merece atención: en cuanto la configuración se cachea en producción (php artisan config:cache), env() no devuelve nada fuera de los archivos de configuración. El valor debe leerse por tanto vía config(), no vía env(), en cualquier otro lugar de la aplicación:

// config/services.php
return [
    'stripe' => [
        'secret' => env('STRIPE_SECRET_KEY'),
    ],
];

// Dans le code applicatif : config(), jamais env()
$key = config('services.stripe.secret');

En Node.js, leer un archivo .env ya no exige una dependencia externa: el flag nativo --env-file basta, y los valores llegan a process.env. El mismo mecanismo se traslada a un despliegue en producción.

# Chargement natif, sans paquet supplémentaire
node --env-file=.env server.js
// server.js — les valeurs sont dans process.env
const dsn = process.env.DATABASE_URL;
if (!dsn) {
  throw new Error("DATABASE_URL manquante : vérifier le fichier .env");
}

En el build de front, Vite expone al cliente solo el subconjunto con prefijo y lo hace accesible mediante import.meta.env. La frontera es nítida: el servidor lo ve todo, el navegador solo ve el prefijo público.

// Accessible dans le navigateur — donc PUBLIC
const apiBase = import.meta.env.VITE_API_URL;

Comparar los métodos de almacenamiento

El archivo .env cubre el puesto de desarrollo. Muestra sus límites en cuanto hay que compartir secretos en equipo o rotarlos con regularidad. La tabla siguiente sitúa cada enfoque.

MétodoAlcanceSecretos sensiblesCompartir en equipo
Archivo .envMáquina local, un proyectoAceptable si queda fuera del repoManual, frágil
Variables de sistema / shellMáquina o sesiónNinguno
direnv (archivo .envrc)Por carpeta, automáticoComo .envManual
Gestor de secretos (Vault, 1Password, SOPS)Equipo, multiproyectoSí, cifrado y auditadoCentralizado, trazable

direnv: cargar y descargar automáticamente

Reexportar variables a mano al cambiar de proyecto es fuente de errores. La herramienta direnv lo resuelve cargando las variables de una carpeta en cuanto el terminal entra en ella, y descargándolas al salir. El archivo .envrc puede incluso delegar en el .env ya presente:

# .envrc — chargé automatiquement à l'entrée du dossier
dotenv .env
export PATH="$PWD/bin:$PATH"

# Autorisation explicite (sécurité de direnv) :
#   direnv allow

Este enfoque encaja bien con un puesto ya equipado con un conjunto bien elegido de herramientas de línea de comandos: los secretos siguen al contexto, sin variables sueltas arrastradas de un proyecto a otro.

Un secreto que nunca entró en el historial de Git no hace falta revocarlo con prisas.

Rotación, compartición y producción

Tres reflejos distinguen a un proyecto maduro. Primero la rotación: una clave comprometida —o simplemente antigua— se reemplaza, y la aplicación debe tolerar ese cambio sin un redespliegue pesado. Segundo la compartición: más allá de dos o tres personas, intercambiar archivos .env por mensajería se vuelve inmanejable y peligroso; un gestor de secretos centraliza el acceso y deja rastro de quién leyó qué. Tercero la producción: allí los valores los inyecta la plataforma de alojamiento o el orquestador, nunca un archivo versionado, y el mínimo privilegio se aplica clave a clave.

Una fuga merece un procedimiento escrito de antemano: revocar la clave expuesta en el proveedor, generar una nueva, purgar el valor del historial si entró en él y revisar los registros de acceso. Una clave publicada en un repositorio público debe considerarse comprometida en el minuto, aunque el repo se vuelva privado de inmediato: los bots de indexación escrutan los commits sin parar.

Lo que hay que recordar

Gestionar secretos no exige una herramienta exótica para empezar: un .gitignore escrito primero, un .env.example versionado y una lectura hecha por la capa que cada framework prevé cubren la gran mayoría de los proyectos. La sofisticación —direnv, un gestor de secretos, el cifrado de archivos— se añade cuando el equipo crece o los secretos se multiplican. El único gesto no negociable es el primero: nada sensible en el historial de Git.

En mis proyectos, la regla que hago respetar primero no es técnica sino ritual: el .gitignore y el .env.example se escriben antes que una sola línea de lógica de negocio. He visto fugarse demasiadas claves de Stripe y contraseñas SMTP porque el .env se había subido «solo una vez» al inicio del proyecto, cuando nadie prestaba atención. La rotación sistemática tras la salida de alguien del equipo también me ha ahorrado más de un disgusto. — Simon Janvier

Para profundizar: el factor Config de la metodología Twelve-Factor App, referencia fundacional sobre la separación entre código y configuración.

Compartir LinkedIn Bluesky Hacker News E-mail

Leer también