Docker Compose restart Ignores New Environment Variables: Recreate the Container
Changing .env, env_file, or an environment: value does not update a running container after docker compose restart. The restart command starts the existing container with the environment it received at creation time. Re-render the Compose configuration, then recreate the affected service with docker compose up.
Why restart keeps the old value
Compose resolves variables and writes the resulting environment into the container configuration when the container is created. docker compose restart stops and starts that same container; it does not apply changes from compose.yaml or the files used for interpolation.
There are two checks worth keeping separate:
| Check | What it answers |
|---|---|
docker compose config --environment | Which shell and .env values Compose will use for interpolation |
docker compose config | What the merged Compose model contains |
docker inspect | What the existing container was actually created with |
The distinction matters because a value can be correct in the newly rendered model while the old container still has the previous value. The Docker Compose variable interpolation guide covers the separate precedence rules for .env, --env-file, shell variables, and environment:.
Render and inspect before recreating
From the directory that contains the intended Compose project, render the model first:
docker compose config --environmentdocker compose configDo not paste the full rendered output into a public issue if it contains passwords or tokens. For a service named web, inspect the value stored in its current container:
docker compose ps webdocker inspect "$(docker compose ps -q web)" \ --format '{{range .Config.Env}}{{println .}}{{end}}' \ | grep '^APP_MODE='If the rendered value and the inspected value differ, the container is stale. If they match but the application still behaves differently, inspect the application’s own configuration loading and the distinction between build-time and runtime variables.
Recreate only the service that changed
For a runtime environment change, recreate the service without rebuilding its image:
docker compose up -d --no-deps --force-recreate web--force-recreate makes the lifecycle explicit, while --no-deps avoids restarting dependencies that did not change. If the Compose file’s configuration changed and you omit --force-recreate, docker compose up -d web can still detect the change and recreate the service. The explicit flag is useful in a deployment script when the update must not depend on change detection.
Named volumes are preserved during ordinary recreation, but data written only to the old container’s writable layer is not a volume backup. Check the service’s volume configuration before removing anything, especially when changing database credentials or storage paths.
Rebuild only when the image also changed
An environment change is not automatically an image change. If you edited the Dockerfile or the image’s build arguments, rebuild before recreating:
docker compose build webdocker compose up -d --no-deps webIf the value is used by a frontend build, changing a runtime .env file after the image was built may be too late. Re-run the image build with the intended build-time variables, then verify the generated assets. A container can have the new runtime environment and still serve JavaScript that was compiled with the old value.
Verify the new container at the application boundary
After recreation, check both Docker and the application:
docker compose ps webdocker compose logs --tail=100 webdocker inspect "$(docker compose ps -q web)" \ --format '{{range .Config.Env}}{{println .}}{{end}}' \ | grep '^APP_MODE='Then call a health endpoint or exercise the code path that consumes the variable. Do not print secrets as proof; use a safe mode name, a feature flag, or a redacted diagnostic endpoint. If the value is a secret, consider a Docker secret or the hosting platform’s secret store instead of adding it to logs or a rendered configuration artifact.
The operational rule is: restart reuses a container, while up can create a new one from the current model. Use the smallest targeted recreation that matches the change and verify the value from the new container, not only from the file on disk.
FAQ
Q: Does restart: always reload values from .env?
A: No. restart: always is a restart policy for the container runtime. It does not recreate the container or re-read Compose configuration after the container exists.
Q: Should I always run docker compose down first?
A: No. For one service, docker compose up -d --no-deps --force-recreate service is narrower and keeps unrelated services running. Use a wider stop and recreate only when the project-wide change requires it.
Q: Why is a frontend still using the old environment value after recreation?
A: The value may have been embedded during the image build. Rebuild the image with the intended build-time inputs, recreate the service, and inspect the generated asset rather than only the container environment.
References:
Report a typo or broken link, or suggest a related topic.