Variables de entorno de Docker Compose que no se aplican: .env, env_file, precedencia y recreación de contenedores

¿Los cambios en .env no se aplican en Docker Compose? Distingue interpolación y entorno del contenedor con un ejemplo reproducible, revisa env_file, las sobrescrituras del Shell y la diferencia entre restart y recrear, con comandos para PowerShell.

Si las variables de entorno de Docker Compose no se aplican, distingue dos operaciones: .env y --env-file proporcionan variables para resolver la configuración de Compose, mientras que environment y env_file del servicio las pasan al contenedor. Tras cambiar la configuración, restart no actualiza el entorno de un contenedor existente. Comprueba el resultado resuelto y aplica los cambios con up -d.

Al seguir un tutorial de despliegue, es habitual que un valor aparezca en .env pero no dentro del contenedor, o que la aplicación siga usando una dirección antigua después de editarlo y reiniciar. Conviene investigar por capas: «archivos de entrada → configuración de Compose → entorno del contenedor → lectura por la aplicación».

Este artículo se aplica a Compose V2 y contenedores Linux, incluido Docker Desktop en modo de contenedores Linux. La documentación se revisó el 4 de noviembre de 2026. Los comandos se basan en la documentación oficial; no se ejecutaron contenedores Docker en el entorno de preparación de este artículo.

Si mantienes servicios autoalojados como Joplin Server o Syncthing, utiliza primero este ejemplo aislado para comprender las sobrescrituras y después revisa la configuración real.

Adónde envía las variables cada una de las cuatro opciones

Opción Dónde se utiliza Función principal
.env Archivo de entrada convencional del proyecto de Compose Proporciona valores para interpolaciones como ${VAR}
--env-file ./deploy.env Opción de línea de comandos de Compose Selecciona explícitamente un archivo de entrada para la interpolación
env_file: ./app.env Configuración de un servicio concreto Inyecta las variables del archivo en el contenedor de ese servicio
environment: Configuración de un servicio concreto Establece, referencia o sobrescribe directamente variables del contenedor

Un mismo archivo puede cumplir ambas funciones, pero debes declararlo explícitamente. Colocar .env en el directorio no pasa automáticamente todas sus variables a todos los contenedores.

Por ejemplo, si .env contiene APP_MODE=production pero el servicio no declara ninguna variable de entorno, normalmente el contenedor no recibirá APP_MODE por ese motivo. Al añadir environment: APP_MODE: "${APP_MODE}" al servicio, se conecta esa cadena de transmisión.

Consulta la guía oficial para establecer variables de entorno del contenedor.

Observar las sobrescrituras en un proyecto sin datos de la aplicación

Primero comprueba la CLI y el host Docker al que está conectada realmente.

1
2
3
docker compose version
docker context show
docker info

Crea un directorio independiente llamado compose-env-lab con estos tres archivos. No añadas el servicio experimental directamente a un proyecto de producción.

1
2
3
4
compose-env-lab/
├── compose.yaml
├── .env
└── app.env

compose.yaml:

1
2
3
4
5
6
7
8
9
services:
  probe:
    image: alpine:3.22
    env_file:
      - ./app.env
    environment:
      APP_MODE: "${APP_MODE:-development}"
      APP_LABEL: "${APP_LABEL:?APP_LABEL is required}"
    command: ["sleep", "3600"]

.env:

1
2
3
APP_MODE=production
APP_LABEL=compose-env-lab
ONLY_FOR_COMPOSE=not-in-container

app.env:

1
2
APP_MODE=from-env-file
APP_COLOR=blue

El ejemplo no publica puertos ni utiliza volúmenes o permisos privilegiados. Debes descargar la imagen desde un registro accesible para tu host Docker. Mantén los archivos sin cambios hasta terminar el experimento inicial para poder comparar los resultados.

Ejecuta primero lo siguiente en ese directorio:

1
2
3
docker compose -p compose-env-lab config -q
docker compose -p compose-env-lab config --environment
docker compose -p compose-env-lab config

Que config -q termine correctamente solo significa que la configuración supera la validación. config --environment muestra las variables utilizadas para la interpolación; config sin esa opción muestra el modelo del servicio combinado y resuelto. Ninguno demuestra que el contenedor se haya creado ni que la aplicación haya leído los valores.

Estas salidas pueden contener contraseñas. Revísalas solo en un terminal de confianza y elimina los valores sensibles antes de compartirlas. Consulta las opciones en docker compose config.

Leer solo las variables necesarias después del arranque

1
2
3
docker compose -p compose-env-lab up -d
docker compose -p compose-env-lab ps
docker compose -p compose-env-lab exec probe printenv APP_MODE APP_LABEL APP_COLOR

Si el terminal que inicia Compose no tiene variables del mismo nombre que sobrescriban estos valores, la salida esperada, en orden, es:

1
2
3
production
compose-env-lab
blue

APP_MODE procede de la interpolación con .env y sobrescribe la entrada del mismo nombre en app.env. APP_COLOR se inyecta mediante el env_file del servicio. APP_LABEL es obligatorio: si falta o está vacío, se produce un error al resolver la configuración.

Consulta ahora por separado la variable que no se ha declarado para pasarla al contenedor:

1
docker compose -p compose-env-lab exec probe printenv ONLY_FOR_COMPOSE

No debería haber salida y el comando debería devolver un estado distinto de cero. Es el resultado normal del experimento: .env no es un archivo que inyecte automáticamente todas sus variables en el contenedor.

Por qué el terminal sobrescribe los valores de .env

Cuando Compose resuelve ${APP_MODE}, tiene prioridad una variable del mismo nombre presente en el Shell que lo inicia. Si el archivo indica production pero el resultado es staging, comprueba primero el entorno del terminal.

En Bash puedes consultar y eliminar la variable experimental así:

1
2
3
printenv APP_MODE
unset APP_MODE
docker compose -p compose-env-lab config --environment

El equivalente en PowerShell es:

1
2
3
Get-Item Env:APP_MODE -ErrorAction SilentlyContinue
Remove-Item Env:APP_MODE -ErrorAction SilentlyContinue
docker compose -p compose-env-lab config --environment

Antes de eliminar una variable del terminal actual, comprueba que otra tarea no la necesita. Las tareas del IDE, los trabajos de CI y los servicios del sistema también pueden heredar un entorno diferente al de un terminal abierto manualmente.

Para reducir la ambigüedad del directorio de trabajo, especifica explícitamente los archivos de configuración y entrada en los comandos de despliegue:

1
2
docker compose -p myapp -f ./compose.yaml --env-file ./deploy.env config -q
docker compose -p myapp -f ./compose.yaml --env-file ./deploy.env config

Sustituye myapp por el nombre del proyecto existente; no cambies el nombre de un despliegue de producción sin motivo. El nombre del proyecto interviene en los nombres de contenedores, redes y volúmenes predeterminados. Cambiarlo puede generar otro conjunto de recursos.

Las rutas relativas de --env-file parten del directorio de trabajo donde ejecutas el comando; las rutas relativas habituales del env_file de un servicio parten de la ubicación del archivo de Compose. Varios archivos de Compose, --project-directory y COMPOSE_FILE pueden complicar estas relaciones. Para investigar, empieza por rutas explícitas que reduzcan el ámbito del problema.

Si especificas varios archivos de entrada para la interpolación, los posteriores pueden sobrescribir las entradas del mismo nombre de los anteriores:

1
docker compose --env-file .env --env-file .env.prod config

Las variables del mismo nombre ya presentes en el Shell pueden seguir teniendo prioridad. Comprueba los detalles de búsqueda del .env predeterminado según tu versión de la CLI; consulta las reglas de interpolación y carga de archivos de Compose.

Comprobar por separado la precedencia dentro del contenedor

Una vez identificadas las entradas de interpolación, revisa cómo establece finalmente el servicio las variables del contenedor. En los casos habituales de asignación explícita, puedes guiarte por estas relaciones:

Caso Efecto en el resultado
docker compose run -e APP_MODE=debug Sobrescribe la variable de este contenedor temporal
Establecer APP_MODE en el environment del servicio Sobrescribe el valor del mismo nombre en el env_file del servicio
Enumerar varios env_file en un servicio Los archivos posteriores sobrescriben los valores coincidentes de los anteriores
ENV en el Dockerfile de la imagen Se conserva si no lo sobrescribe una configuración de ejecución del mismo nombre

El propio valor de environment puede proceder de la interpolación del Shell o de .env. Separa «de dónde se resuelve el valor» de «qué campo del servicio lo pasa al contenedor». Las declaraciones que solo indican el nombre de una variable también pueden eliminarla si no se resuelve su valor. Al investigar, utiliza preferentemente asignaciones explícitas.

Prueba una sobrescritura temporal en el experimento:

1
docker compose -p compose-env-lab run --rm -e APP_MODE=debug probe printenv APP_MODE

La salida esperada es debug. Esto crea un contenedor de un solo uso y no modifica el contenedor probe iniciado antes con up -d. Tampoco debes tratar run -e como una opción general de up.

Consulta los límites completos y los ejemplos de transmisión de valores en la guía oficial de precedencia de variables de entorno.

Por qué restart mantiene el valor antiguo después de modificar un archivo

Las variables de entorno de un contenedor se determinan al crearlo. docker compose restart reinicia contenedores existentes, pero no recrea su entorno a partir de la configuración modificada.

Cambia APP_MODE a staging en el .env experimental y compara lo siguiente:

1
2
3
docker compose -p compose-env-lab config
docker compose -p compose-env-lab restart probe
docker compose -p compose-env-lab exec probe printenv APP_MODE

Si el contenedor utilizaba inicialmente production, debería conservar ese valor después del reinicio. En ese momento, los archivos de configuración y el contenedor en ejecución están en estados diferentes.

Tras confirmar que la configuración resuelta es correcta, aplica el cambio:

1
2
docker compose -p compose-env-lab up -d probe
docker compose -p compose-env-lab exec probe printenv APP_MODE

Compose normalmente detecta los cambios de configuración y recrea los contenedores de los servicios afectados. Si necesitas realmente forzar la recreación, utiliza:

1
docker compose -p compose-env-lab up -d --force-recreate probe

La recreación interrumpe el servicio, por lo que debes programarla en la ventana de mantenimiento correspondiente. La arquitectura real determina si también hay que actuar sobre dependencias como las bases de datos. No recrees todo el proyecto por costumbre.

Los volúmenes montados se siguen utilizando según la configuración, pero pueden perderse los cambios temporales de la capa de escritura del contenedor. Antes de proceder, confirma que los datos de la aplicación están almacenados realmente en ubicaciones persistentes. Consulta las descripciones oficiales de restart y up.

Errores habituales con signos de dólar, valores vacíos y booleanos

Expandir una variable dentro del contenedor

Compose suele procesar primero las referencias $VAR del archivo de Compose. Para que el Shell del contenedor lea la variable, utiliza $$ e invoca explícitamente un Shell:

1
2
3
4
5
6
services:
  probe:
    image: alpine:3.22
    environment:
      APP_MODE: "production"
    command: ["sh", "-c", "printf '%s\\n' \"$$APP_MODE\""]

Este es un ejemplo independiente de un servicio breve que imprime el valor y termina. $$ impide que Compose expanda la variable en el host; sh -c realiza la expansión dentro del contenedor. Introducir una variable en un array de argumentos que no pasa por un Shell no habilita automáticamente la expansión del Shell.

Consulta la sintaxis en Compose Interpolation.

Una cadena vacía no equivale a una variable sin definir

${VAR:-default} utiliza el valor predeterminado si la variable no existe o está vacía. ${VAR-default} solo lo utiliza si la variable no existe. ${VAR:?message} resulta útil para entradas que no deben estar vacías y evita que direcciones o rutas vacías lleguen a la ejecución.

No ocultes temporalmente ajustes de producción mediante cadenas vacías sin documentar el motivo. Un valor vacío explícito en un servicio puede sobrescribir una configuración válida de env_file.

En YAML, conviene escribir como cadenas los valores que parezcan booleanos:

1
2
3
environment:
  FEATURE_ENABLED: "false"
  WORKER_COUNT: "2"

Esto solo garantiza que se pase una cadena. Que la aplicación interprete "false" como desactivado o considere verdadera cualquier cadena no vacía depende de su propio analizador de configuración.

Por qué la aplicación no cambia aunque la configuración y el contenedor sean correctos

Comprueba primero si la aplicación admite ese nombre de variable y si existen fuentes de mayor prioridad, como archivos de configuración o argumentos de línea de comandos. APP_URL, BASE_URL y PUBLIC_URL no forman un protocolo universal y no se pueden sustituir libremente entre proyectos.

Después comprueba cuándo se lee el valor: algunos ajustes del frontend se incorporan a archivos estáticos al construir la imagen. Establecer variables en tiempo de ejecución no reescribe los artefactos existentes. Si el proyecto necesita argumentos de compilación, configura build.args o su script de arranque específico según la documentación del proyecto.

Por último, verifica que estás consultando el servicio y la instancia correctos. El worker, el web y el scheduler de un proyecto pueden ser tres contenedores distintos. Actualizar uno no modifica los otros dos.

Observación Siguiente paso
config sigue mostrando el valor antiguo Revisa las rutas de entrada, las sobrescrituras del Shell y la combinación de archivos
config es correcto, pero exec printenv muestra el valor antiguo Revisa el nombre del proyecto, el Docker context y la recreación del contenedor
El valor del contenedor es correcto, pero la aplicación no cambia Revisa el nombre de variable, la precedencia de la aplicación, el momento de lectura y la instancia a la que accedes
exec falla porque el contenedor no está en ejecución Empieza por ps -a y los registros del servicio

En el experimento puedes ejecutar directamente:

1
2
docker compose -p compose-env-lab ps -a
docker compose -p compose-env-lab logs --tail 100 probe

Las imágenes de aplicaciones pueden no incluir printenv o un Shell. En ese caso, utiliza sus comandos de diagnóstico o pide a un administrador que revise la configuración del contenedor y oculte los datos sensibles. Evita instalar herramientas adicionales en una imagen de producción solo para investigar.

Contraseñas, reversión y limpieza del experimento

No escribas contraseñas reales en un repositorio de ejemplo ni pegues la salida completa de config, inspect o de todas las variables de env. .env es un archivo de texto plano y no ofrece cifrado. Puedes incluir en el repositorio un .env.example sin credenciales; restringe la lectura de los archivos reales de despliegue según los requisitos del proyecto y exclúyelos del control de versiones.

Si la aplicación puede leer credenciales desde archivos, considera Compose secrets. Permite proporcionar un secret autorizado como archivo dentro del contenedor, normalmente en /run/secrets/<name>. Las variables _FILE son una convención adoptada por algunas imágenes, no una función que todas las aplicaciones admitan automáticamente. También debes proteger los archivos de origen locales; consulta la guía oficial de Compose secrets.

Antes de modificar la configuración de producción, guarda la configuración y las entradas de entorno anteriores, y anota el nombre del proyecto, la versión de la imagen y los argumentos del comando. Para revertir, restaura esos archivos, comprueba config -q con los mismos argumentos, ejecuta up -d y verifica el comportamiento de la aplicación. Revertir la configuración no sustituye una copia de seguridad de la base de datos ni garantiza que se puedan deshacer las migraciones ya realizadas por la aplicación.

Al terminar el experimento, ejecuta lo siguiente en el directorio compose-env-lab:

1
docker compose -p compose-env-lab down

Este ejemplo no declara volúmenes, por lo que no necesitas añadir -v. No conviertas este comando experimental en una limpieza global. Para mantener el almacenamiento, consulta la guía de limpieza de espacio en disco de Docker.

Al terminar la investigación, confirma por separado que la configuración resuelta es la esperada, que el contenedor en ejecución tiene los valores nuevos y que el comportamiento real de la aplicación ha cambiado. Son tres capas distintas. Comprobarlas una por una evita editar .env repetidamente mientras se persigue una causa equivocada.