Una aplicación cambia de comportamiento según el equipo, el usuario o el entorno donde se ejecuta. Las variables de entorno permiten comunicarle esos valores dinámicos sin modificar el código, desde la ruta de una carpeta hasta el modo de producción o la dirección de una base de datos. Explico cómo funcionan, cómo configurarlas en Windows, Linux y macOS, y qué precauciones conviene aplicar para no convertir un ajuste práctico en un problema de seguridad.
La configuración correcta separa el código de los valores que cambian
- Definición Las variables son pares formados por un nombre y un valor que un proceso puede leer durante su ejecución.
- Ámbitos Pueden existir solo en una terminal, afectar a un usuario o aplicarse a todo el sistema.
-
Comandos Linux y macOS utilizan normalmente
export, mientras PowerShell emplea$env:NOMBRE. -
Seguridad Un archivo
.envno cifra las credenciales y nunca debería subirse al repositorio. - Despliegues Docker y las plataformas CI/CD permiten inyectar configuración distinta en cada entorno.

Qué son y cómo llegan a una aplicación
Una variable de entorno es un dato de configuración expresado como un par NOMBRE=valor. El sistema operativo lo pone a disposición de un proceso, y este puede leerlo cuando arranca o mientras funciona. Por ejemplo, LANG=es_ES.UTF-8 puede influir en el idioma, mientras PORT=3000 indica en qué puerto debe escuchar un servidor.
La idea importante es que el valor vive fuera del código fuente. Una misma aplicación puede conectarse a una base de datos local durante el desarrollo y a un servicio gestionado en producción usando exactamente el mismo programa, pero con configuraciones diferentes.
El proceso suele recibir una copia del entorno de su proceso padre. Por eso, una variable creada en una terminal normalmente está disponible para los programas lanzados desde ella, pero no necesariamente para una aplicación que ya estaba abierta o para otra terminal independiente. Esta herencia explica muchos errores que parecen inexplicables al principio.
Variables predefinidas y variables de aplicación
El sistema incluye valores habituales como PATH, HOME, USER, TEMP o USERPROFILE. PATH es especialmente relevante porque contiene las carpetas donde la terminal busca ejecutables cuando escribimos comandos como node, python o git.
Las variables creadas por una aplicación tienen otro propósito. Nombres como DATABASE_URL, API_BASE_URL, LOG_LEVEL o APP_ENV describen la configuración que necesita ese proyecto. Yo prefiero usar nombres claros y consistentes, normalmente en mayúsculas y con guiones bajos, porque así se localizan rápido en scripts y registros de despliegue.
Para qué sirven en el desarrollo de software
Su utilidad principal está en separar la lógica estable de los valores que cambian entre máquinas. Esto evita editar archivos cada vez que se cambia de ordenador, se prueba una API distinta o se publica una nueva versión.
-
Configuración por entorno:
APP_ENV=developmentpuede activar mensajes detallados, mientrasAPP_ENV=productionaplica un comportamiento más restrictivo. -
Rutas y puertos: una aplicación puede recibir
UPLOAD_DIRoPORTsin asumir una ubicación fija. -
Servicios externos:
API_BASE_URLpermite cambiar entre una API de pruebas y la real. -
Opciones de ejecución:
LOG_LEVEL=debugayuda a diagnosticar errores, aunque conviene desactivarlo en producción. - Automatización: scripts de compilación, pruebas y despliegue pueden reutilizarse con distintos valores.
También ayudan a trabajar en equipo. Cada desarrollador puede tener una base de datos local y unas credenciales propias sin introducir cambios personales en los archivos compartidos. El proyecto debe incluir, eso sí, un archivo de ejemplo como .env.example con los nombres necesarios y valores ficticios.
No todo debe convertirse en una variable. Una regla de formato, una ruta crítica del programa o una opción que jamás cambia suele encajar mejor en la configuración versionada. Cuando se externaliza absolutamente todo, el sistema gana flexibilidad pero pierde trazabilidad y facilidad de diagnóstico.
Cómo configurarlas en Windows, Linux y macOS
Linux y macOS
En una terminal compatible con Bash o Zsh, una variable temporal se define así:
export API_BASE_URL="http://localhost:8080"
export PORT="3000"Solo afectará a esa sesión y a los procesos que se lancen desde ella. Para comprobar el valor se puede usar echo "$PORT" o printenv PORT. Para eliminarlo, el comando es unset PORT.
Si se necesita cargarla automáticamente, puede añadirse a ~/.bashrc, ~/.zshrc o ~/.profile, según el shell y el tipo de sesión. Después hay que abrir una terminal nueva o recargar el archivo con source ~/.zshrc. Yo suelo probar primero el cambio de forma temporal; así evito dejar una configuración incorrecta en todos los inicios de sesión.
Windows PowerShell
En PowerShell, la sintaxis para la sesión actual es distinta:
$env:API_BASE_URL = "http://localhost:8080"
$env:PORT = "3000"Para consultar las variables disponibles se puede ejecutar Get-ChildItem Env: o leer una concreta con $env:PORT. El equivalente habitual en el símbolo del sistema es set PORT=3000, pero esa asignación también queda limitada a la ventana actual.
Para una configuración persistente, Windows ofrece el cuadro de Variables de entorno dentro de las propiedades avanzadas del sistema. PowerShell también permite establecer valores de usuario con [Environment]::SetEnvironmentVariable("PORT","3000","User"). Las aplicaciones abiertas antes del cambio pueden conservar el entorno anterior, por lo que a menudo es necesario reiniciarlas.
La diferencia entre temporal y permanente
| Alcance | Duración | Uso recomendable |
|---|---|---|
| Sesión de terminal | Hasta cerrar la terminal | Pruebas rápidas y diagnósticos |
| Usuario | Hasta modificarla o eliminarla | Herramientas y preferencias personales |
| Sistema | Disponible para varios usuarios y servicios | Configuración compartida del equipo |
| Proceso o contenedor | Mientras se ejecuta ese servicio | Aplicaciones aisladas y despliegues |
El alcance más amplio no siempre es el mejor. Una ruta de desarrollo puede pertenecer al usuario, mientras que un valor para un servicio concreto debería quedarse en su proceso o contenedor. Cuanto menor sea el ámbito, menor será también la posibilidad de afectar accidentalmente a otras aplicaciones.
Archivos .env, contenedores y despliegues automáticos
Muchos proyectos utilizan un archivo llamado .env para reunir valores locales:
APP_ENV=development
PORT=3000
DATABASE_URL=postgresql://usuario:contraseña@localhost:5432/appEste formato resulta cómodo, pero no es universal. El sistema operativo no carga automáticamente un .env; debe hacerlo el framework, una biblioteca o la herramienta de ejecución. En Node.js, Python, Laravel, Docker Compose y otros entornos, la lectura depende de la configuración concreta del proyecto.
La práctica básica es añadir .env a .gitignore y publicar únicamente .env.example. El archivo de ejemplo documenta nombres, formatos y valores de muestra, pero nunca debe contener una contraseña real. Si una credencial ya se ha subido a Git, borrarla del último commit no basta: hay que revocarla y sustituirla.
Docker Compose
En Docker, los valores pueden pasar al contenedor desde el archivo de composición, un archivo de entorno o la línea de comandos. Un ejemplo sencillo sería:
services:
web:
image: mi-aplicacion:latest
environment:
APP_ENV: production
PORT: 8080La aplicación dentro del contenedor verá esos valores como parte de su entorno. Esto permite usar la misma imagen en pruebas y producción con configuraciones distintas. Sin embargo, incluir una contraseña directamente en docker-compose.yml puede exponerla al repositorio, a las copias de seguridad o a los registros de cambios.
Para información sensible, prefiero mecanismos de secretos proporcionados por el orquestador o el proveedor de alojamiento. Una variable de entorno sirve para configuración; no ofrece por sí sola cifrado, control de acceso ni ocultación frente a cualquier proceso con permisos suficientes.
CI/CD y variables por entorno
Las plataformas de integración y despliegue continuo permiten definir valores a nivel de proyecto, organización o entorno. Así, una canalización puede usar una URL de pruebas en la rama de desarrollo y otra de producción al publicar una versión aprobada.
Conviene distinguir entre una variable normal, que puede ser visible en la configuración o en los registros, y un secreto protegido. Las claves de API, tokens, certificados y contraseñas deben almacenarse en el gestor de secretos de la plataforma, limitarse al entorno que las necesita y evitarse en comandos que puedan quedar registrados.
Errores habituales que provocan fallos difíciles de ver
Confundir la sintaxis del shell
export PORT=3000, set PORT=3000 y $env:PORT="3000" no son intercambiables. Cada orden pertenece a una herramienta distinta. Copiar un comando de Linux en PowerShell puede crear un valor incorrecto o no crear ninguno.
Modificar PATH sin conservar lo anterior
Reemplazar PATH por una sola carpeta puede hacer que desaparezcan comandos esenciales del sistema. En sistemas Unix se suele ampliar con export PATH="$PATH:/nueva/ruta"; en Windows, la edición debe conservar las entradas existentes. Las rutas duplicadas no suelen romper nada de inmediato, pero dificultan saber qué versión de un ejecutable se está utilizando.
Olvidar las comillas y los tipos
Los valores se manejan normalmente como texto. Si una contraseña contiene espacios, caracteres especiales o símbolos interpretados por el shell, necesita una forma de escape adecuada. Además, PORT=3000 llega a muchas aplicaciones como la cadena "3000", por lo que el programa debe convertirla a número y validar que esté dentro de un rango razonable.
Esperar que una aplicación ya abierta vea el cambio
Una variable modificada en la terminal no actualiza automáticamente los procesos que ya estaban ejecutándose. Reiniciar el servidor, el IDE o el servicio suele ser la solución. En Windows, también puede hacer falta cerrar y volver a abrir el programa que inicia la aplicación.
Lee también: Cómo borrar las cookies en Chrome, Edge, Firefox y Safari
Usar un nombre distinto al que espera el código
DATABASE_URL, DATABASE_URI y DB_URL pueden parecer equivalentes para una persona, pero son nombres diferentes para el programa. Mantener una lista de variables obligatorias y validar su presencia al arrancar produce errores claros en lugar de fallos silenciosos a mitad de una petición.
Cómo usarlas sin crear un riesgo de seguridad
El error más extendido consiste en creer que una variable de entorno es un almacén seguro. En realidad, puede aparecer en volcados de procesos, paneles de depuración, registros, herramientas de monitorización o mensajes de error. No debe imprimirse su valor en logs, especialmente durante una incidencia.
- Guarda las credenciales en un gestor de secretos cuando el proyecto sale del ordenador local.
- Concede a cada servicio solo los permisos que necesita y utiliza tokens con caducidad cuando sea posible.
- Valida que las variables obligatorias existan antes de iniciar la aplicación.
- Comprueba el formato de URLs, puertos, rutas y valores booleanos.
- Revisa el historial de Git si una clave se expone y rótala de inmediato.
- Evita pasar secretos como argumentos de comandos, porque pueden quedar visibles en el historial o en la lista de procesos.
También aplico una separación sencilla entre valores públicos y sensibles. El nombre de una API, el nivel de logs o un puerto no tienen el mismo riesgo que un token de acceso. Tratar todo como secreto complica el trabajo; tratar todo como público puede provocar una filtración seria.
En aplicaciones web, estas variables suelen leerse en el servidor. Exponerlas al navegador o incluirlas durante la compilación puede hacer que cualquier visitante las vea. Antes de usar un prefijo destinado al cliente, compruebo qué valores terminan realmente en el código JavaScript distribuido.
Una configuración sencilla que sigue siendo mantenible
Para un proyecto pequeño, mi método consiste en documentar cada nombre en .env.example, cargar los valores reales fuera del repositorio y validar la configuración al inicio. Después pruebo el mismo arranque en desarrollo, pruebas y producción con un conjunto de valores específico para cada entorno.
La clave no está en crear muchas variables, sino en que cada una tenga un propósito claro, un responsable y un ámbito controlado. Cuando una aplicación falla, saber de dónde procede cada valor reduce mucho el tiempo de diagnóstico y evita cambios improvisados en el código.
Bien utilizadas, estas variables convierten la configuración en una pieza flexible del software. No sustituyen a un gestor de secretos ni corrigen una arquitectura deficiente, pero ofrecen una base limpia para ejecutar la misma aplicación en varios equipos, contenedores y entornos sin duplicar el código.