Are you confused about when to use ARG versus ENV in your Dockerfiles? You're not alone! This comprehensive guide will help you understand the key differences, use cases, and best practices for both build arguments (ARG) and environment variables (ENV) in Docker.
Quick Reference
| Feature | ARG | ENV |
|---|---|---|
| Available during build | ✅ | ✅ |
| Available in running container | ❌ | ✅ |
| Can be set in Dockerfile | ✅ | ✅ |
| Can be overridden at build time | ✅ | ❌ |
| Persists in final image | ❌ | ✅ |
| Can be used in FROM instruction | ✅ | ❌ |
Key Differences
The fundamental difference between ARG and ENV lies in their scope and persistence:
- ARG is only available during the build process
- ENV sets environment variables that persist in the running container
Understanding ARG
Build arguments (ARG) are variables that you can pass to Docker during the image build process using the --build-arg flag.
Basic ARG Syntax
# Declare the argument ARG VERSION=latest # Use the argument FROM ubuntu:${VERSION} Build command:
docker build --build-arg VERSION=20.04 -t my-ubuntu . ARG Scoping Rules
- ARGs declared before
FROMare only available duringFROMinstruction - To use
ARGafterFROM, you need to redeclare it - Each
FROMinstruction clears all ARGs declared before it
# Global ARG ARG BASE_IMAGE=ubuntu # Available in FROM FROM ${BASE_IMAGE}:latest # Need to redeclare to use after FROM ARG BASE_IMAGE RUN echo "Building from ${BASE_IMAGE}" Understanding ENV
Environment variables (ENV) are set in your image and are available both during build and when the container runs.
Basic ENV Syntax
# Set a single environment variable ENV APP_VERSION=1.0.0 # Set multiple environment variables ENV NODE_ENV=production \ PORT=3000 \ APP_HOME=/app ENV Persistence
ENVs persist across build stages and in the final container:
# Stage 1: Build FROM node:16 AS builder ENV NODE_ENV=production RUN echo "Building in ${NODE_ENV}" # Stage 2: Runtime FROM node:16-slim # NODE_ENV needs to be redefined if needed in this stage ENV NODE_ENV=production Real-World Examples
1. Building Different Versions of an Application
# Build argument for version control ARG NODE_VERSION=16 # Base image with specified version FROM node:${NODE_VERSION} # Environment variable for runtime configuration ENV NODE_ENV=production # Redeclare ARG if needed after FROM ARG NODE_VERSION RUN echo "Node.js version: ${NODE_VERSION}" # Application setup WORKDIR /app COPY package*.json ./ RUN npm install COPY . . # Runtime configuration ENV PORT=3000 \ APP_NAME=my-awesome-app CMD ["npm", "start"] 2. Configurable Build Process
# Build-time configuration ARG INSTALL_DEV_DEPS=false ARG ENABLE_TESTING=false FROM node:16 WORKDIR /app COPY package*.json ./ # Redeclare ARGs after FROM ARG INSTALL_DEV_DEPS ARG ENABLE_TESTING # Conditional installation of dependencies RUN if [ "$INSTALL_DEV_DEPS" = "true" ]; then \ npm install; \ else \ npm install --production; \ fi COPY . . # Conditional testing RUN if [ "$ENABLE_TESTING" = "true" ]; then \ npm test; \ fi # Runtime configuration ENV NODE_ENV=production \ LOG_LEVEL=info CMD ["npm", "start"] Best Practices
-
Use ARG for Build Flexibility
- Version numbers
- Base image selection
- Build-time configuration
-
Use ENV for Runtime Configuration
- Application settings
- Service endpoints
- Feature flags
Default Values
# Provide sensible defaults for ARGs ARG VERSION=latest ARG NODE_ENV=production # ENVs should also have defaults ENV PORT=3000 \ LOG_LEVEL=info - Documentation
# Document your build arguments # Required: VERSION - Specify the application version to build # Optional: NODE_ENV - Build environment (default: production) ARG VERSION ARG NODE_ENV=production - Security Considerations
- Never use ARG or ENV for secrets
- Use Docker secrets or environment files for sensitive data
- Remember that ENVs are visible in the image history
Common Pitfalls
- ARG Scope Confusion
# Won't work as expected ARG VERSION FROM ubuntu:${VERSION} # Need to redeclare ARG VERSION RUN echo ${VERSION} - Build-time vs Runtime Values
# Wrong: Using ARG for runtime configuration ARG API_URL=http://api.example.com # Correct: Use ENV for runtime configuration ENV API_URL=http://api.example.com - Missing Defaults
# Risky: No default value ARG VERSION # Better: Include a default ARG VERSION=latest Advanced Usage
Combining ARG and ENV
# Build argument with default ARG NODE_ENV=production # Set ENV based on ARG ENV NODE_ENV=${NODE_ENV} # Now NODE_ENV persists in the container # but can be configured at build time Multiple Build Stages
# Build stage FROM node:16 AS builder ARG BUILD_MODE=production ENV NODE_ENV=${BUILD_MODE} RUN npm install && npm run build # Production stage FROM node:16-slim ARG BUILD_MODE=production ENV NODE_ENV=${BUILD_MODE} COPY --from=builder /app/dist ./dist Using Docker Compose
services: app: build: context: . args: - NODE_VERSION=16 - BUILD_MODE=development environment: - NODE_ENV=development - PORT=3000 Conclusion
Understanding the difference between ARG and ENV is crucial for building flexible and maintainable Docker images. Use ARG for build-time configuration and ENV for runtime settings. Remember that ARGs are only available during build, while ENVs persist in the running container.
By following these guidelines and best practices, you can create more maintainable and configurable Docker images while avoiding common pitfalls.
Top comments (0)