Docker Compose Env Interpolation - Empty Default Yields Wrong Values in CI
Compose interpolates ${VAR} from the environment and .env. When a variable is unset it defaults to an empty string (with a warning), which can silently produce a wrong image tag or config. The :-, -, and :? modifiers control defaults and required-variable behavior.
What this error means
A docker compose up warns The "TAG" variable is not set. Defaulting to a blank string and then uses an empty value (e.g. image: myorg/api: → :latest or invalid). Or a ${VAR:?msg} fails the run because a required variable is missing.
WARN[0000] The "TAG" variable is not set. Defaulting to a blank string.
# image: myorg/api:${TAG} -> myorg/api: (empty tag)
# or required: error: required variable "DB_PASSWORD" is missing a value: set it in .envCommon causes
Unset variable defaults to empty
Compose substitutes an unset ${VAR} with an empty string and only warns. An empty tag or value flows through silently, producing a wrong reference or config.
Confusing :- vs - default syntax
${VAR:-default} uses the default when VAR is unset OR empty; ${VAR-default} only when VAR is unset (an empty VAR stays empty). Choosing the wrong one yields surprising values.
Required variable not provided
A ${VAR:?error message} is meant to fail loudly when VAR is missing. The failure is intentional - provide the value.
How to fix it
Provide explicit defaults with :-
Default required-but-optional variables so an unset value does not become empty.
services:
api:
image: myorg/api:${TAG:-latest} # default to latest if unset/emptyMake truly-required variables fail fast
Use :? so a missing required value stops the run with a clear message.
environment:
DB_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in the environment or .env}How to prevent it
- Default optional variables with
${VAR:-default}. - Mark required variables with
${VAR:?message}to fail fast. - Run
docker compose configto verify interpolated values before running.