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
FROM
are only available duringFROM
instruction - To use
ARG
afterFROM
, you need to redeclare it - Each
FROM
instruction 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)