Start with the exact assignment
If the Compose file says CC_LEVEL: literal, changing a shell variable will not replace that literal. If it says CC_LEVEL: ${CC_LEVEL:-fallback}, the shell can provide the interpolation input. Those are different configurations.
Case 1: a literal beats the service file
# app.env
CC_LEVEL=fileservices:
probe:
image: busybox:1.37
env_file: app.env
environment:
CC_LEVEL: literalCC_LEVEL=shell docker compose configOur resolved environment is CC_LEVEL: literal. The shell did not override this literal, and the explicit service mapping replaced the value from app.env. This is why “the shell always wins” is not a useful diagnosis on its own.
Case 2: the mapping uses interpolation
Now replace only the assignment with:
environment:
CC_LEVEL: ${CC_LEVEL:-fallback}For this second fixture, we used .env with CC_LEVEL=dot-env, cli.env with CC_LEVEL=cli-file and app.env with CC_LEVEL=service-file.
| Input to the command | Resolved CC_LEVEL |
|---|---|
| Shell CC_LEVEL=shell, --env-file cli.env | shell |
| No shell value, --env-file cli.env | cli-file |
| No shell value, no --env-file | dot-env |
All three outcomes were measured with the same fixture content. The explicit environment mapping then supplies the resolved value to the service model.
An empty value is still a value
# .env
CC_EMPTY=
# environment fragment
CC_A: ${CC_EMPTY:-fallback}
CC_B: ${CC_EMPTY-fallback}In our model check, CC_A became fallback; CC_B became an empty string. The colon changes how an empty input is handled. Check for an empty export when a default behaves unexpectedly.
A short debugging sequence
- Locate the exact service and key in your resolved model.
- Check whether the assignment is literal or interpolated.
- For interpolation, compare the specific shell input with the explicitly selected file.
- Check whether an
environmentmapping replaces a service-file value. - If the model is correct, investigate the running container separately.
Our tests stop at model resolution. They do not execute docker compose run -e or test image ENV; those additional runtime precedence rules are covered in Docker’s full reference. Keep production configuration output private.
Sources & evidence
Documentation checked 12 Sep 2026. Our fixture evidence: