Docker Environment Variable Precedence Tester

Work out which value the container actually gets. Prefix each line with its source: run, environment, env_file, dockerfile or shell.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Test. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

Three layered sources

environment: wins, and the Dockerfile value is only the floor

dockerfile: ENV PORT=8080
env_file: PORT=9090
environment: PORT=3000

A variable set in your shell

Reaches nothing, and the Dockerfile default is what the container gets

shell: API_KEY=fromshell
dockerfile: ENV API_KEY=default

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Exporting a variable in your shell and expecting the container to see it

    Containers do not inherit the shell's environment. Compose reads it only for interpolating the compose file.

    Instead:Pass it explicitly with a bare key: environment: [API_KEY].

  2. Putting a value in a shared env_file to override a service's environment:

    environment: is more specific, so it always wins. The env_file value is simply ignored.

    Instead:Remove it from whichever place should not own it, so there is one source to check.

  3. Putting a credential in a Dockerfile ENV

    It is baked into the image metadata and readable with docker history by anybody who can pull the image.

    Instead:Pass it at run time, and use a build secret mount if it is needed during the build.

A container does not inherit your shell

That is the one people lose the most time to, because the same command works in a terminal and the container gets nothing.

The order, highest to lowest

-e on the command line, then environment: in the compose file, then env_file:, then the Dockerfile's ENV. Each is more specific than the one below it, which means a shared env_file cannot override a per-service value, and that is usually discovered by somebody trying exactly that.

Your shell is not on the list

Compose reads your environment only to fill in ${ } while parsing the compose file. To pass a variable from your shell into the container you have to say so, with a bare key and no value: environment: [API_KEY]. That is the only route.

.env is a fourth thing again

It populates ${ } in the compose file, from the project directory. It is not env_file:, it does not reach the container, and the same name can sit in both with different values and nothing will point that out.

Dockerfile ENV is a default and a disclosure

It is the value when nothing else supplies one, and it is baked into the image metadata, so anybody who can pull the image can read it with docker history. A credential in an ENV is a published credential.

A value set in two places is a bug waiting

Not because the resolution is ambiguous, it is not, but because whoever changes the losing one will believe they have changed the behaviour. One place per variable is worth more than knowing the order.

What this cannot see

Anything you did not paste, including whether a variable exists at all. It resolves the sources you describe, in your browser.

More docker tools

Docker Container Image Reference Parser Is that a registry or a Docker Hub user? Dockerfile Linter What this image will do to you later docker run to Kubernetes YAML And the flags that have no equivalent Docker Compose to Kubernetes And why depends_on has no equivalent Docker Logging Driver Generator json-file never rotates Dockerfile Non-Root USER Generator Numeric, or Kubernetes rejects it Docker OCI Image Labels Generator One of them actually does something Docker Hub Pull Rate Limit Calculator Counted per IP, not per person Docker Registry Storage Calculator Deleting a tag frees nothing Docker Build Context Analyzer All of it uploads before anything runs Docker Compose to docker run Converter Names stop resolving Docker Compose Version Migrator version: is obsolete now Docker Compose Network and Port Viewer Everything reaches everything Docker Command Explainer Which flags hand over the host Docker BuildKit Cache Mount Generator apt deletes the cache you just mounted Docker BuildKit Secret Mount Generator ARG is in docker history forever Docker .dockerignore Pattern Tester *.log does not match logs/app.log Docker Image Manifest Viewer unknown/unknown is not broken Docker Image Config Viewer Anyone who can pull can read your Env Docker Registry Token Decoder Check the scope before the credentials Docker HEALTHCHECK Generator Docker does nothing when it fails Docker Network Subnet Calculator 31 networks, then it stops Docker History Analyzer The rm did not save anything Docker Run to Compose Converter Some flags have no equivalent Docker CMD and ENTRYPOINT Tester Why docker stop takes ten seconds Docker Port Mapping Tester -p reaches past your firewall Docker -v to --mount Converter -v invents missing directories Docker Restart Policy Simulator The backoff resets after ten seconds Docker Exit Code Explainer 137 is two different problems Docker CPU Limit Converter --cpu-shares limits nothing Docker Memory Limit Calculator -m 512m allows a gigabyte Docker Compose Interpolation Tester An unset variable is an empty string Docker Compose Override Merge Previewer An override can add a port, never remove one Dockerfile Multi-Stage Build Analyzer Which stages reach the image Dockerignore Validator It is not .gitignore

Elsewhere on the site