ARG, ENV & Build-Time Configuration
ARG or ENV? When to use which? What about .env files? Build-time secrets? This article untangles Docker's configuration mechanisms, showing you how to build flexible, secure, and maintainable images.
📋 At a Glance
| Aspect | Details |
|---|---|
| Topic | ARG, ENV, .env files, build-time secrets, configuration patterns |
| Complexity | Intermediate |
| Prerequisites | Part 3 (Build Process), Part 6 (Multi-Stage) |
| Key Insight | ARG is for build customization, ENV is for runtime behavior |
| Time to Master | 2 hours |
🎯 What You'll Learn
- ARG vs ENV - when to use each, scope rules, security implications
- Build arguments - parameterizing builds safely
- Environment variables - runtime configuration patterns
- Secrets management - keeping sensitive data out of images
- Configuration patterns - 12-factor app principles in Docker
🔥 Production Story: The Wrong Config in Production
A team deployed to production. Everything passed staging tests. Then orders started failing - the app was hitting staging payment APIs.
BASH(6 lines)CodeLoading syntax highlighter...
DOCKERFILE(5 lines)CodeLoading syntax highlighter...
BASH(7 lines)CodeLoading syntax highlighter...
DOCKERFILE(5 lines)CodeLoading syntax highlighter...
YAML(6 lines)CodeLoading syntax highlighter...
🧠 Mental Model: Configuration Layers
┌──────────────────────────────────────────────────────────────────────────┐ │ DOCKER CONFIGURATION LAYERS │ │ │ │ BUILD TIME RUNTIME │ │ ═══════════ ═══════ │ │ │ │ ┌──────────────────┐ ┌──────────────────────────────┐ │ │ │ ARG │ │ docker run -e │ │ │ │ (--build-arg) │ │ docker-compose env │ │ │ │ │ │ k8s ConfigMap/Secret │ │ │ │ • Build only │ │ │ │ │ │ • Not in image │ │ • Overrides ENV │ │ │ │ • Visible in │ │ • Not in image │ │ │ │ history! │ │ • Per-container │ │ │ └────────┬─────────┘ └──────────────┬───────────────┘ │ │ │ │ │ │ │ Can set │ Overrides │ │ ▼ ▼ │ │ ┌──────────────────────────────────────────────────────────────────────┐│ │ │ ENV ││ │ │ (in Dockerfile) ││ │ │ ││ │ │ • Baked into image ││ │ │ • Default values ││ │ │ • Available at build AND runtime ││ │ │ • Overridable at runtime ││ │ └──────────────────────────────────────────────────────────────────────┘│ │ │ │ Priority (highest wins): │ │ 1. docker run -e / compose environment │ │ 2. ENV in Dockerfile │ │ 3. Base image ENV │ │ │ └──────────────────────────────────────────────────────────────────────────┘
🔬 Deep Dive
ARG: Build-Time Variables
ARG defines variables that can be passed at build time:
DOCKERFILE(11 lines)CodeLoading syntax highlighter...
BASH(6 lines)CodeLoading syntax highlighter...
DOCKERFILE(14 lines)CodeLoading syntax highlighter...
BASH(5 lines)CodeLoading syntax highlighter...
ENV: Runtime Variables
ENV sets environment variables that persist in the image:
DOCKERFILE(11 lines)CodeLoading syntax highlighter...
- Persists in image metadata
- Available during build (after definition)
- Available at runtime
- Overridable with
docker run -e
DOCKERFILE(8 lines)CodeLoading syntax highlighter...
The .env File Confusion
Docker has multiple .env file contexts:
BASH(3 lines)CodeLoading syntax highlighter...
YAML(7 lines)CodeLoading syntax highlighter...
YAML(5 lines)CodeLoading syntax highlighter...
BASH(3 lines)CodeLoading syntax highlighter...
BASH(9 lines)CodeLoading syntax highlighter...
Configuration Patterns
DOCKERFILE(9 lines)CodeLoading syntax highlighter...
BASH(5 lines)CodeLoading syntax highlighter...
DOCKERFILE(13 lines)CodeLoading syntax highlighter...
YAML(13 lines)CodeLoading syntax highlighter...
DOCKERFILE(11 lines)CodeLoading syntax highlighter...
BASH(5 lines)CodeLoading syntax highlighter...
Secrets Management
DOCKERFILE(7 lines)CodeLoading syntax highlighter...
DOCKERFILE(13 lines)CodeLoading syntax highlighter...
BASHCodeLoading syntax highlighter...
YAML(11 lines)CodeLoading syntax highlighter...
JAVASCRIPT(5 lines)CodeLoading syntax highlighter...
Multi-Stage ARG Propagation
DOCKERFILE(16 lines)CodeLoading syntax highlighter...
DOCKERFILE(12 lines)CodeLoading syntax highlighter...
Debugging Configuration
BASH(11 lines)CodeLoading syntax highlighter...
⚠️ Common Mistakes
Mistake 1: Using ARG for Secrets
DOCKERFILE(7 lines)CodeLoading syntax highlighter...
Mistake 2: Baking Environment URLs
DOCKERFILE(8 lines)CodeLoading syntax highlighter...
Mistake 3: Not Understanding ARG Scope
DOCKERFILE(9 lines)CodeLoading syntax highlighter...
🐛 Debug This: The Disappearing Variable
A developer reports: "My ARG works in the first stage but disappears in the final stage!"
DOCKERFILE(10 lines)CodeLoading syntax highlighter...
FROM starts a new stage with a clean ARG scope.ARG APP_VERSION=1.0.0is defined globally (before first FROM)- First stage implicitly has access to global ARGs
- Second stage starts fresh - no ARGs defined
${APP_VERSION}is empty because it wasn't redeclared
DOCKERFILE(13 lines)CodeLoading syntax highlighter...
DOCKERFILE(7 lines)CodeLoading syntax highlighter...
💻 Exercises
Exercise 1: ARG vs ENV Behavior
⭐ Difficulty: Easy | ⏱️ Time: 15 minutes
DOCKERFILE(28 lines)CodeLoading syntax highlighter...
Exercise 2: Multi-Stage ARG Propagation
⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes
DOCKERFILE(18 lines)CodeLoading syntax highlighter...
BASH(8 lines)CodeLoading syntax highlighter...
Exercise 3: BuildKit Secrets
⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes
BASH(31 lines)CodeLoading syntax highlighter...
Exercise 4: Environment-Agnostic Image
⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes
Create a Dockerfile and compose files for an app that:
- Has ONE image used for all environments
- Configuration differs by environment via compose files
- Defaults work for local development
BASH(19 lines)CodeLoading syntax highlighter...
Exercise 5: Complete Configuration Strategy
⭐⭐⭐⭐ Difficulty: Expert | ⏱️ Time: 30 minutes
Build a complete configuration system:
Requirements: 1. Build-time configuration: - VERSION (embedded in image) - BUILD_DATE (metadata) - FEATURES (enable/disable features) 2. Runtime configuration: - DATABASE_URL (environment-specific) - API_KEY (secret, not in image) - LOG_LEVEL (overridable) 3. Multi-stage build preserving ARGs 4. Proper secrets handling
Deliverables:
- Dockerfile with proper ARG/ENV usage
- docker-compose.yml for development
- docker-compose.prod.yml for production
- Secrets file handling
- Build script with all arguments
🎤 Senior-Level Interview Questions
Q1: Explain the difference between ARG and ENV in Docker.
"ARG and ENV serve different purposes in the Docker build lifecycle:
- Available only during build
- Passed via
--build-arg - Not persisted in the final image (except in history!)
- Resets at each FROM statement
- Can have defaults:
ARG VERSION=1.0
- Persisted in the image
- Available at build time (after declaration) AND runtime
- Can be overridden with
docker run -e - Doesn't reset across stages
- Truly embedded in image
DOCKERFILE(2 lines)CodeLoading syntax highlighter...
This gives you:
- Build-time flexibility via ARG
- Runtime accessibility via ENV
- Overridability at both stages
docker history. Never use ARG for secrets. Even with --squash, the values can be extracted. Use BuildKit --mount=type=secret instead."Q2: How do you handle secrets at build time?
"There are several approaches with different security levels:
DOCKERFILE(7 lines)CodeLoading syntax highlighter...
Token is in builder history but not final image.
DOCKERFILE(3 lines)CodeLoading syntax highlighter...
Secret available only during that RUN, not in any layer.
- Fetch from secret manager at runtime
- Use credential helpers
- Proxy through secure service
DOCKERFILECodeLoading syntax highlighter...
- ARG for secrets
- COPY secret files
- ENV with secrets
- Echo/cat secrets in RUN
The key principle: secrets should exist only during specific RUN commands and never be written to any layer."
Q3: How do you manage configuration across multiple environments?
"I follow the 12-factor app principle - one image, environment-specific configuration at runtime:
DOCKERFILE(3 lines)CodeLoading syntax highlighter...
YAML(20 lines)CodeLoading syntax highlighter...
BASH(5 lines)CodeLoading syntax highlighter...
- ConfigMaps for non-sensitive config
- Secrets for sensitive values
- Same image, different config per namespace
- Build time (ARG): Version, build flags, feature toggles for compilation
- Image (ENV): Safe defaults, NODE_ENV=production
- Runtime: URLs, credentials, environment-specific values
This ensures: same image in staging and production, only configuration differs."
Q4: What happens when you reference an undefined ARG or ENV?
"The behavior differs between ARG and ENV:
- Silently empty string
- No build failure
- Can cause subtle bugs
DOCKERFILE(2 lines)CodeLoading syntax highlighter...
- Also empty string
- Silent unless explicitly checked
- Require ARGs when necessary:
DOCKERFILE(2 lines)CodeLoading syntax highlighter...
- Provide safe defaults:
DOCKERFILE(2 lines)CodeLoading syntax highlighter...
- Fail fast for required values:
DOCKERFILE(5 lines)CodeLoading syntax highlighter...
- Document required variables:
DOCKERFILE(5 lines)CodeLoading syntax highlighter...
I prefer explicit failures over silent empty values. Configuration bugs are easier to debug when they fail immediately."
Q5: How do ARGs interact with Docker's build cache?
"ARG values are part of the cache key for layers that use them:
DOCKERFILE(3 lines)CodeLoading syntax highlighter...
If VERSION changes:
- First RUN: cache miss (uses VERSION)
- Second RUN: also cache miss (parent changed)
If VERSION stays same:
- Both RUNs: cache hit
DOCKERFILE(4 lines)CodeLoading syntax highlighter...
- Put ARGs as late as possible to maximize cache
- Separate build-affecting ARGs from metadata ARGs
- Don't use timestamps in ARGs unless you want cache bust
DOCKERFILE(13 lines)CodeLoading syntax highlighter...
For cache-busting deliberately:
DOCKERFILE(2 lines)CodeLoading syntax highlighter...
docker build --build-arg CACHEBUST=$(date +%s)"📝 Summary & Key Takeaways
ARG vs ENV Quick Reference
| Aspect | ARG | ENV |
|---|---|---|
| Scope | Build only | Build + Runtime |
| Persisted | No (but in history!) | Yes |
| Override | --build-arg | docker run -e |
| Secrets | ❌ Never | ❌ Never |
| Resets at FROM | Yes | No |
Configuration Hierarchy
Runtime -e / compose environment (highest priority) ↓ ENV in Dockerfile ↓ Base image ENV ↓ Application defaults (lowest priority)
Best Practices
- ARG for build variants - versions, feature flags
- ENV for runtime defaults - safe, overridable values
- Never bake secrets - Use BuildKit mounts or runtime injection
- One image, many configs - Environment differences at runtime
- Explicit over implicit - Fail fast on missing required values
📋 Quick Reference
Dockerfile Syntax
DOCKERFILE(16 lines)CodeLoading syntax highlighter...
Build Commands
BASH(10 lines)CodeLoading syntax highlighter...
Runtime Configuration
BASH(8 lines)CodeLoading syntax highlighter...
📅 Review Schedule
| Day | Task | Time |
|---|---|---|
| Day 1 | Review ARG vs ENV table | 5 min |
| Day 3 | Do Exercise 1 (ARG vs ENV behavior) | 15 min |
| Day 7 | Implement BuildKit secrets in a project | 20 min |
| Day 14 | Audit project for configuration anti-patterns | 20 min |
| Day 30 | Create environment-agnostic image for real project | 30 min |
📚 Series Navigation
| Previous | Current | Next |
|---|---|---|
| Part 7: Base Image Selection | Part 8: Build Configuration | Part 9: Resource Management |
- Part 0: How to Use This Series
- Part 1: Container Internals
- Part 2: Image Anatomy
- Part 3: Build Process Deep Dive
- Part 4: Networking Internals
- Part 5: Dockerfile Optimization Patterns
- Part 6: Multi-Stage Builds: Beyond Basics
- Part 7: Base Image Selection & Security
- Part 8: ARG, ENV & Build-Time Configuration ← You are here
- Part 9: Container Resource Management