Introduction to Docker Build Arguments and Environment Variables
You've probably seen Dockerfiles with variables sprinkled throughout. Maybe you've copied a Dockerfile from a tutorial and tried to change the port number, only to realize the variable was hardcoded elsewhere. Or you've built the same image multiple times with different settings and wished there was a cleaner way to handle configuration.
Docker provides two instructions for handling variables in images: ARG for build-time configuration and ENV for runtime environment variables. Understanding the difference between them and when to use each will make your Dockerfiles more maintainable and your container images more flexible.
Build-Time Variables with ARG
The ARG instruction defines a variable that users can pass at build time. Think of ARG as a parameter you set when you run docker build. The variable exists only during the build process and isn't available inside the running container.
When you build this image, you can override the default values:
The ARG instruction has a few important characteristics:
- Default values: You can provide a default value that's used if the user doesn't specify the argument
- Scope: Variables are available in the FROM instruction and all subsequent instructions
- Lifetime: They disappear after the build completes
- Visibility: They're not visible inside the running container
ARG vs ENV: The Key Differences
The most common confusion is between ARG and ENV. Here's the fundamental difference:
| Aspect | ARG | ENV |
|---|---|---|
| When available | Only during build | Available at runtime |
| Container visibility | Not visible | Visible inside container |
| Purpose | Build-time configuration | Runtime configuration |
| Persistence | Lost after build | Persists in container |
If you try to use an ARG inside a RUN command, it won't work because the variable isn't available at that point:
You need to declare the ARG before the FROM instruction to use it in FROM, and you need to declare it before the RUN instruction to use it there.
Runtime Variables with ENV
The ENV instruction sets environment variables that will be available in the container. These variables persist after the container starts and can be accessed by processes running inside the container.
When this container runs, the environment variables are available to all processes:
You can also set multiple variables in a single ENV instruction:
ENV in Different Contexts
ENV variables can be set in different places in your Dockerfile:
Combining ARG and ENV
The most powerful pattern is to use ARG for build-time configuration and ENV to pass those values to the runtime. This gives you the best of both worlds: flexibility during build and configuration at runtime.
Now you can build different variants of your image:
Both images will have the correct environment variables set at runtime, but you can override them when running the container:
Practical Example: Multi-Stage Build with Configuration
Here's a complete example showing how to use ARG and ENV together in a multi-stage build:
This Dockerfile demonstrates several best practices:
- Build arguments control the Node.js version and environment
- Build-time ENV captures metadata like build time and git commit
- Runtime ENV sets the actual configuration for the application
- Multi-stage build keeps the final image small by only copying what's needed
Best Practices
1. Use ARG for Version Pinning
Pin versions of dependencies and tools using ARG to make your builds reproducible:
2. Validate ARG Values
You can validate ARG values in your Dockerfile to catch errors early:
3. Use .dockerignore
Don't commit .env files or sensitive configuration to your repository. Use .dockerignore to exclude them:
4. Document Your Build Arguments
Add comments to your Dockerfile explaining what arguments are available:
5. Use BuildKit for Better ARG Support
Enable BuildKit for improved ARG handling and caching:
Or add to your Dockerfile:
Common Pitfalls
Pitfall 1: Using ARG in RUN Commands
As mentioned earlier, ARG is not available in RUN commands unless declared before them:
Pitfall 2: Overriding ENV with ENV
If you set an ENV variable and then try to override it with another ENV, the second one wins:
Pitfall 3: Hardcoding Values
Avoid hardcoding values that should be configurable:
Conclusion
Understanding the difference between ARG and ENV is crucial for writing effective Dockerfiles. Use ARG for build-time configuration that changes between builds, and use ENV for runtime configuration that needs to be available when the container runs.
The combination of both gives you the flexibility to build different variants of your image while keeping the runtime configuration consistent. This pattern is especially useful in CI/CD pipelines where you might build development, staging, and production images from the same Dockerfile.
When you're ready to deploy your applications, platforms like ServerlessBase can help you manage these container images and handle the complex orchestration of environments, making it easier to focus on writing good Dockerfiles rather than managing deployment infrastructure.
Next Steps
Now that you understand ARG and ENV, you can explore:
- Docker Compose: How to pass build arguments and environment variables to services
- Multi-stage builds: Using ARG to control different stages of your build
- Docker secrets: Securely managing sensitive data at runtime
- CI/CD integration: Automating build arguments in your deployment pipeline