Setting Environment Variables in Docker Build: Understanding ARG vs ENV

Nov 21, 2025 · Programming · 50 views · 7.8

Keywords: Docker | Environment Variables | ARG Instruction | ENV Instruction | Container Build

Abstract: This technical article provides an in-depth analysis of environment variable management during Docker image builds, focusing on the fundamental differences between ARG and ENV instructions. Through comprehensive code examples and scenario analysis, it explains why ARG variables become invisible after build completion and how to properly use ENV instructions to make environment variables available at container runtime. The article also covers scope rules for build arguments, variable inheritance in multi-stage builds, and best practices for real-world development.

Overview of Environment Variables in Docker Builds

Environment variable management is a common yet frequently misunderstood aspect of Docker image construction. Many developers expect environment variables set via build arguments to remain available in the final container when using the docker build command, but reality often contradicts these expectations. This discrepancy primarily stems from insufficient understanding of the ARG and ENV instructions in Dockerfile.

Core Differences Between ARG and ENV

The ARG instruction defines build-time variables that are exclusively available during the image construction process. Once the image build completes, these variables do not appear in the final container's environment. Conversely, environment variables set with the ENV instruction are not only usable during the build process but also persist into the final image, making them available when containers are run.

Consider this typical erroneous example:

FROM ubuntu:latest
ARG TEST_ENV=something

Build command used:

docker build -t myimage --build-arg TEST_ENV="test" .

Checking environment variables after container execution:

docker exec containerid printenv

The result will not show the TEST_ENV variable, precisely because ARG variables have a lifecycle limited to the build process.

Correct Methods for Environment Variable Configuration

To make environment variables available at container runtime, the ENV instruction must be used. Here's the proper implementation approach:

FROM ubuntu:latest
ENV RUN_TIME=default_value

Alternatively, combine ARG and ENV to achieve build-time configurable environment variables:

FROM ubuntu:latest
ARG BUILD_TIME_ARG=default_build_value
ENV RUN_TIME_ENV=$BUILD_TIME_ARG

This approach allows setting the BUILD_TIME_ARG value via the --build-arg parameter during build, which then gets passed to the RUN_TIME_ENV environment variable, ultimately making it available in the container.

Practical Application Examples

Let's demonstrate the differences through a complete example:

FROM ubuntu:latest

# Build-time variable
ARG BUILD_TIME_VAR=build_default

# Runtime environment variable
ENV RUN_TIME_VAR=run_default

# Convert build-time variable to runtime variable
ENV CONVERTED_VAR=$BUILD_TIME_VAR

# Using variables during build process
RUN echo "Build-time variable value: $BUILD_TIME_VAR" > /build_info.txt
RUN echo "Runtime variable value: $RUN_TIME_VAR" >> /build_info.txt
RUN echo "Converted variable value: $CONVERTED_VAR" >> /build_info.txt

# Recording final environment state
RUN printenv > /final_env.txt

Build command:

docker build -t test-image --build-arg BUILD_TIME_VAR="custom_build_value" .

Running container and examining results:

docker run -it test-image cat /build_info.txt
docker run -it test-image cat /final_env.txt
docker run -it test-image printenv

From the output, we can clearly observe:

Scope and Inheritance Rules

Understanding variable scope and inheritance rules becomes crucial in complex multi-stage build scenarios.

ARG Variables in Global Scope

ARG variables defined in the Dockerfile's global scope are not automatically inherited into individual build stages:

# Global scope
ARG GLOBAL_VAR=global_value

FROM ubuntu AS stage1
# GLOBAL_VAR inaccessible here
RUN echo "Stage 1: Attempting to access global variable"  # Output empty

FROM ubuntu AS stage2
# Explicit declaration required for access
ARG GLOBAL_VAR
RUN echo "Stage 2: Global variable value: $GLOBAL_VAR"

Variable Inheritance Within Stages

Variables defined within a stage are automatically inherited by its child stages:

FROM ubuntu AS base
ARG STAGE_VAR=stage_default
ENV STAGE_ENV=env_default

FROM base AS child
# Can access variables defined in parent stage
RUN echo "Child stage - ARG: $STAGE_VAR"
RUN echo "Child stage - ENV: $STAGE_ENV"

Best Practice Recommendations

Based on practical development experience, we recommend the following best practices:

1. Clear Variable Purpose Definition

When writing Dockerfiles, clearly define the purpose of each variable:

2. Security Considerations

ARG variable values are preserved in image history, making them unsuitable for sensitive information. For passwords, API keys, and other sensitive data, use Docker's secrets mechanism instead.

3. Default Value Configuration

Set reasonable default values for important ARG variables to ensure the build process functions correctly even without external parameters:

ARG APP_VERSION="1.0.0"
ARG NODE_ENV="production"
ENV NODE_ENV=$NODE_ENV

4. Combined Usage Scenarios

In real-world projects, combining ARG and ENV is often necessary:

# Build-time configuration
ARG APPLICATION_VERSION
ARG BUILD_TIMESTAMP

# Runtime environment
ENV APP_VERSION=$APPLICATION_VERSION
ENV BUILD_TIME=$BUILD_TIMESTAMP
ENV NODE_ENV=production

# Application-specific configuration
ENV DB_HOST=localhost
ENV DB_PORT=5432

Common Issues and Solutions

Issue 1: Variables Invisible in Container

Symptoms: Variables set via --build-arg are not visible when running the container.

Cause: Used ARG instead of ENV.

Solution: Use ENV instruction or pass ARG values through ENV.

Issue 2: Variable Loss in Multi-stage Builds

Symptoms: Unable to access variables defined in previous stages during subsequent build stages.

Cause: Incorrect understanding of variable scope rules.

Solution: Explicitly declare variables in each requiring stage, or ensure variables are defined in parent stages.

Issue 3: Unexpected Variable Value Overwriting

Symptoms: Environment variable values don't match expectations.

Cause: Possibly defined same-name variables in multiple locations.

Solution: Unify variable definition locations and avoid duplicate definitions.

Conclusion

Proper understanding and usage of environment variables during Docker build processes is an essential skill for containerized application development. While ARG and ENV share functional similarities, they possess fundamental differences: ARG serves build-time parameterization, while ENV addresses runtime environment configuration. Through judicious combination of these two instructions, developers can create Docker images that are both flexible and configurable, meeting deployment requirements across different environments.

In practical development, we recommend adhering to these principles: define clear variable purposes, set reasonable default values, prioritize security considerations, and understand scope rules. Only by following these guidelines can developers fully leverage the advantages of Docker environment variables and construct high-quality containerized applications.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.