Docker Compose Ignoring Your Environment Variables

Three different mechanisms pass env vars (interpolation, .env files, environment: blocks) and each fails in its own way. Identify which layer is silently dropping your value.

What you'll see

Root causes

Interpolation vs container environment confusion

${VAR} in compose.yaml substitutes at CONFIG parse time (from your shell/.env file); the environment: block sets what the CONTAINER sees. Setting the shell var changes interpolation, not the container's env, and vice versa.

.env file location and precedence

Compose reads .env from the project directory (where you run the command, by default) — not the compose file's folder. Shell vars override .env values, and .env doesn't affect already-created containers until recreate.

Old container not recreated

up -d reuses unchanged containers: env changes need an explicit recreate (up -d --force-recreate or compose down/up).

Fix it

  1. Inspect what the container actually got
    docker exec <ct> env | grep -i <var> ; docker inspect <ct> --format '{{json .Config.Env}}' | python3 -m json.tool
  2. See what compose will interpolate before deploying
    docker compose config   # renders the final config with all substitutions applied
  3. Reload the container after changing .env
    docker compose up -d --force-recreate   # env only applies at container creation
  4. For files-not-variables: use env_file
    # services:
    #   app:
    #     env_file: ./.env.production   # loads KEY=VALUE lines into the container

Field note

docker compose config is the ground truth — if the value is wrong there, the container was never the problem. Lists/quotes in .env files aren't parsed like shell: no quotes, no spaces around =.

Common questions

Why does $VAR in my compose file stay empty?

It's interpolated from the shell and the .env file in the compose project dir at command time — not from the container's or image's environment. Print it with docker compose config to see the substitution result.

Do containers pick up .env changes automatically?

No. Environment is baked in at container creation. Recreate with docker compose up -d --force-recreate (or down/up) after changing .env or environment:.

Ship it right the first time

A production-shaped compose stack: healthchecks, resource limits, log rotation. Never debug a boot race again.

Docker Production Starter — $19 →

One-time. Yours to modify. Instant download from the NinjaOps template store.

Get new fixes by email

One short email when new fixes and production templates drop. No spam, unsubscribe anytime.

Partner pick — sponsored

Vultr — our lab-environment pick for this stack

Spin up a cloud server in 60 seconds and reproduce this fix yourself — pay by the hour.

Get Vultr →
Also vetted

Sentry — Free tier: see the exact line of code that broke, before users report it.

Get Sentry →

We earn a commission if you buy through our links — it never costs you extra. More vetted tools on our picks hub · comparing clouds? DigitalOcean vs Vultr and vs AWS · full deals: DigitalOcean · Vultr · NordLayer · Semrush