Pass environment variables from docker-compose to container at build stage
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Docker Compose can pass configuration into two different phases: image build time and container runtime. The distinction matters because a value needed by RUN npm ci or a compiler step must be available while the image is being built, not only after the container starts.
Build-Time Variables Use ARG, Not environment
In a Compose file, the environment section configures the running container. It does not automatically expose values to the Dockerfile during docker compose build. For build-time values, use build.args in Compose and ARG in the Dockerfile.
The matching Dockerfile declares each build argument explicitly:
The important rule is simple. ARG exists during the image build. ENV exists in the final image and is available when the container runs. If you want a build argument to remain available later, copy it into an environment variable as shown above.
Supplying Values from a .env File
Compose can interpolate values from a local .env file. That keeps the Compose file reusable across development, staging, and production.
When you run docker compose build, Compose resolves the placeholders and forwards them as build arguments. This is often enough for non-secret settings such as a language runtime version, feature flag, or package mirror URL.
When to Promote a Build Argument to ENV
Many developers only need the value while building. For example, a dependency installer may need PIP_INDEX_URL or a frontend build may need APP_ENV to select the correct bundle mode. In that case, leave it as ARG.
If the application also needs the value when the container starts, add a corresponding ENV line:
That pattern makes the value available in both phases. Be deliberate here. Every ENV line becomes part of the image metadata, so do not promote sensitive values without understanding the exposure.
A Practical Verification Workflow
One easy way to confirm that build arguments are wired correctly is to echo them during a build step:
Then run:
Using --no-cache avoids confusion when Docker reuses an earlier layer that was built with a different argument value. Once the build behaves as expected, remove noisy debug steps from the Dockerfile.
Common Pitfalls
The most common mistake is putting a variable under environment and expecting a RUN instruction to see it. That variable only exists for the started container, so the build still fails.
Another common issue is using an ARG in the FROM line without declaring it early enough. If a build argument is part of the base image tag, declare it before FROM. If you also need it later in the file, declare it again after FROM.
Caching also causes confusion. Docker may reuse a cached layer built with an older argument value. Rebuild with docker compose build --no-cache when you are debugging changed inputs.
Finally, do not pass secrets such as tokens or passwords with plain ARG unless you accept that they may appear in the image history or build logs. For sensitive data, prefer BuildKit secrets or another secret-management approach.
Summary
- Use
build.argsindocker-compose.ymlandARGin the Dockerfile for build-time values. - Use
environmentfor runtime container variables, not forRUNsteps in the build. - Copy an
ARGintoENVonly when the container also needs the value after startup. - Use
.envinterpolation to keep Compose files portable across environments. - Avoid putting secrets in normal build arguments, and disable cache when debugging changed values.

