✦ For everyone, free.

Practical knowledge for real and everyday life

Home

16.4.1.4 Compose Environment Missing

A focused guide to Compose Environment Missing, connecting core concepts with practical Docker and container operations.

Compose environment missing describes a service starting without an expected environment variable actually being set, despite what appears to be correct configuration in the Compose file, and the cause is almost always traceable to one of several specific gaps in how Compose resolves and merges environment variables from its various possible sources, .env files, env_file references, the environment key, and the shell's own exported variables.

Confirming the variable is genuinely missing

Before investigating further, confirming directly inside the running container that the variable is actually absent, rather than present but with an unexpected value, narrows the investigation correctly from the start:

docker compose exec api env | grep DATABASE_URL
docker compose config | grep -A2 "DATABASE_URL"

The second command, checking the fully resolved configuration Compose actually intends to apply, is the more reliable first check, since it shows what Compose believes should be set, before checking what is actually present inside the running container.

The .env file is not the same as env_file

A frequent point of confusion is conflating Compose's special, automatically-loaded .env file, used specifically for variable interpolation within the Compose file itself, with an env_file directive, which explicitly loads a file's contents as environment variables for a specific service:

# .env
DB_HOST=db
services:
  api:
    environment:
      - DATABASE_URL=postgres://${DB_HOST}:5432/app

The .env file here is used only to interpolate ${DB_HOST} into the Compose file's own text at the time Compose parses it; it does not, by itself, set DB_HOST as an environment variable inside the running container at all, unless that variable is also explicitly listed in the service's own environment or env_file configuration.

services:
  api:
    env_file:
      - .env

Using env_file to point at the same file explicitly does load its contents as environment variables for the container, which is a meaningfully different mechanism serving a different purpose than the automatic .env interpolation behavior.

.env file location requirements

Compose's automatic .env file loading specifically looks for a file named exactly .env in the same directory as the Compose file (or the directory docker compose is run from, depending on version and configuration), and a file in a different location or with a different name is not picked up automatically at all:

docker compose --env-file ./config/production.env up -d

For an environment file with a different name or location, the --env-file flag explicitly tells Compose where to find it, which is necessary whenever the file does not match the default expected name and location.

Precedence between multiple environment sources

When the same variable is defined in more than one place, the shell's own exported environment, a .env file, an env_file reference, and the environment key, Compose applies a specific precedence order, and a variable that appears missing might actually be present but overridden by an empty or unset value from a higher-precedence source:

unset DATABASE_URL
docker compose config | grep DATABASE_URL

Checking whether the shell itself has the variable exported, and unsetting it temporarily to test, clarifies whether an empty shell-level variable is unexpectedly overriding a value that would otherwise have been correctly set through the Compose file's own configuration.

Variable not actually referenced correctly in the Compose file

A typo in the variable name within the environment key itself, or a missing equals sign in the list-style syntax, can cause the value to be set under an unintended key, or not set at all:

environment:
  - DATABSE_URL=postgres://db:5432/app

A misspelled key name here (DATABSE_URL instead of DATABASE_URL) sets a variable the application never actually reads, leaving the variable it does read, DATABASE_URL, genuinely unset; reviewing the exact spelling carefully against what the application code actually expects resolves this directly.

Override files not actually being applied

When using a base Compose file alongside an override file specifically to supply additional environment configuration, forgetting to include the override file in the actual command invocation results in only the base file's configuration taking effect, missing whatever the override was meant to add:

docker compose up -d
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d

Compose does automatically pick up a file specifically named docker-compose.override.yml in the same directory without needing to specify it explicitly, but any override file with a different name requires explicit inclusion via additional -f flags; confirming which override files are actually being applied, again most reliably through docker compose config, resolves ambiguity here.

Common mistakes

  • Conflating the automatic .env interpolation mechanism with the env_file directive, expecting variables used only for interpolation to also be automatically available inside the running container.
  • Placing an environment file in a location or with a name Compose does not automatically recognize, without using --env-file to point at it explicitly.
  • Not accounting for environment variable precedence, where an empty or unset value from a higher-precedence source, such as the shell's own environment, unexpectedly overrides a value configured elsewhere.
  • Misspelling a variable name in the environment key, setting an unintended key while leaving the actually-referenced variable name unset.
  • Forgetting to include a non-default-named override file explicitly via -f, causing only the base Compose file's configuration to take effect.

Compose environment missing issues are almost always resolved by checking the fully resolved configuration through docker compose config first, then working through the specific possible gaps, confusing .env interpolation with env_file loading, file location and naming, precedence between sources, and override file inclusion, each of which has a distinct, specific, and quickly verifiable cause.