Problem: AI-Generated Dockerfiles Break Your Environment Variables
You used ChatGPT or Claude to generate a Dockerfile, but your app can't read environment variables at runtime. Database connections fail with "undefined" and API keys are missing.
You'll learn:
- Why AI tools misuse ARG vs ENV
- How to fix build-time vs runtime variable access
- Proper patterns for secrets and configs
Time: 12 min | Level: Intermediate
Why This Happens
AI code generators often confuse ARG (build-time only) with ENV (runtime available). They'll create Dockerfiles that work during docker build but fail when containers actually run.
Common symptoms:
process.env.DATABASE_URLreturnsundefinedin Node.js- Python's
os.getenv('API_KEY')returnsNone - Works locally with
.envfile but not in container - Build succeeds but app crashes on startup
Root cause: Variables defined with ARG disappear after the image is built. Your app needs ENV to access them at runtime.
Solution
Step 1: Identify the Problem Pattern
Check your AI-generated Dockerfile for this common mistake:
# ❌ AI-generated (broken at runtime)
FROM node:22-alpine
ARG DATABASE_URL
ARG API_KEY
COPY . /app
WORKDIR /app
RUN npm install
CMD ["node", "server.js"]
Why it fails: ARG variables only exist during build steps (RUN). When CMD executes, they're gone.
# Test it - see the variables are missing
docker build -t myapp .
docker run myapp printenv | grep DATABASE_URL
# (no output - variable doesn't exist)
Step 2: Fix Runtime Configuration Variables
Use ENV for values needed by your running application:
# ✅ Fixed version
FROM node:22-alpine
# Runtime variables (available to app)
ENV NODE_ENV=production
ENV PORT=3000
COPY . /app
WORKDIR /app
RUN npm install --production
# App reads these at runtime
CMD ["node", "server.js"]
Pass values when running container:
# Override defaults or add new variables
docker run -e DATABASE_URL="postgresql://..." \
-e API_KEY="sk-..." \
myapp
Expected: Your app now sees process.env.DATABASE_URL and process.env.API_KEY.
Step 3: Handle Build-Time Dependencies
Use ARG for values needed during image build only:
# ✅ Proper ARG usage
FROM node:22-alpine
# Build-time only (for npm install from private registry)
ARG NPM_TOKEN
# Make available during build
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && \
npm install && \
rm .npmrc # Don't bake secrets into image
# Runtime variables
ENV NODE_ENV=production
CMD ["node", "server.js"]
Build with ARG:
docker build --build-arg NPM_TOKEN="npm_xyz123" -t myapp .
Why this works: ARG is perfect for install-time credentials that shouldn't persist in the final image.
Step 4: Combine ARG and ENV for Flexibility
Best pattern - allow defaults with override capability:
# ✅ Production-ready pattern
FROM python:3.12-slim
# Accept build-time argument
ARG APP_ENV=production
# Convert to runtime environment variable
ENV APP_ENV=${APP_ENV}
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# App reads APP_ENV at runtime
CMD ["python", "main.py"]
Usage:
# Use default (production)
docker build -t myapp .
# Override for staging
docker build --build-arg APP_ENV=staging -t myapp:staging .
# Further override at runtime if needed
docker run -e APP_ENV=development myapp
Step 5: Handle Secrets Properly
Never use ENV for secrets in production:
# ❌ Never do this - secrets visible in image
ENV API_KEY=sk-1234567890abcdef
# ✅ Use runtime injection instead
# (no API_KEY in Dockerfile at all)
Secure approaches:
# 1. Environment file
docker run --env-file .env.production myapp
# 2. Docker secrets (Swarm/Compose)
docker service create --secret db_password myapp
# 3. Kubernetes secrets
kubectl create secret generic api-keys \
--from-literal=API_KEY=sk-xyz
Verification
Test Environment Variable Access
Create test script:
// test-env.js
console.log('DATABASE_URL:', process.env.DATABASE_URL ? '✓ Set' : '✗ Missing');
console.log('API_KEY:', process.env.API_KEY ? '✓ Set' : '✗ Missing');
console.log('NODE_ENV:', process.env.NODE_ENV);
Run container:
docker run -e DATABASE_URL="postgresql://localhost/test" \
-e API_KEY="test-key" \
myapp node test-env.js
You should see:
DATABASE_URL: ✓ Set
API_KEY: ✓ Set
NODE_ENV: production
Verify Secrets Aren't Baked In
# Check image doesn't contain secrets
docker history myapp --no-trunc | grep -i "api_key\|password\|secret"
# (should return nothing)
If it fails:
- Error: "environment variable not set" - Check you're using
-eflag when running - Secrets visible in history - Rebuild without ENV for secrets, use runtime injection
- Works locally but not in K8s - Check pod spec has env or envFrom configuration
What You Learned
ARG= build-time only (npm tokens, build flags)ENV= runtime available (app config, non-sensitive settings)- Secrets must be injected at runtime, never baked into images
- AI tools often default to ARG when they should use ENV
Pattern to remember:
ARG BUILD_DEPENDENCY_TOKEN # Install-time credentials
ENV APP_SETTING=default # Config with default
# (no secrets in Dockerfile) # Runtime injection only
Limitations:
- ENV variables are visible in
docker inspect- not suitable for secrets - ARG values appear in build cache - avoid sensitive data
- Windows containers use slightly different syntax for variable expansion
Quick Reference Card
| Scenario | Use | Example |
|---|---|---|
| Private npm/pip token | ARG | ARG NPM_TOKENRUN npm install |
| Default app config | ENV | ENV PORT=3000 |
| Database URL | Runtime -e | docker run -e DATABASE_URL=... |
| API keys/passwords | Runtime secret | --env-file or K8s secrets |
| Build variation | ARG → ENV | ARG ENV=prodENV APP_ENV=${ENV} |
Common AI Tool Mistakes:
- ChatGPT/Claude often generate:
ARG DATABASE_URL(wrong - app can't see it) - GitHub Copilot suggests:
ENV API_KEY=hardcoded(wrong - security risk) - They should use: Runtime injection via
-eor--env-file
Pro tip: When asking AI for Dockerfiles, specify: "Use ENV for runtime config, ARG only for build dependencies, and show how to inject secrets at runtime"
Tested on Docker Engine 25.0, Docker Compose v2.24, Node.js 22.x, Python 3.12, macOS & Ubuntu