Docker Environment Variables
What are Environment Variables?
Environment variables are key=value pairs that configure how an application behaves without hardcoding values into the code.
DB_HOST=localhost
DB_PORT=3306
APP_ENV=production
SECRET_KEY=abc123
In Docker, you set these variables when you run a container - the app inside reads them at runtime.
Methods to Set Environment Variables
1. -e flag in docker run
# Set a single variable
docker run -d -e APP_ENV=production my-app
# Set multiple variables
docker run -d \
-e APP_ENV=production \
-e DB_HOST=localhost \
-e DB_PORT=3306 \
-e DB_PASSWORD=secret \
my-app
# Pass a variable from your current shell
export MY_SECRET=abc123
docker run -d -e MY_SECRET my-app # passes the value from your shell
2. --env-file flag in docker run
Creates a file with all variables and passes the file to Docker.
# .env file
APP_ENV=production
DB_HOST=db
DB_PORT=3306
DB_NAME=myapp
DB_USER=appuser
DB_PASSWORD=secret123
REDIS_HOST=redis
SECRET_KEY=very-long-secret-key-here
# Run with env file
docker run -d --env-file .env my-app
# Use a custom env file name
docker run -d --env-file production.env my-app
3. ENV instruction in Dockerfile
Sets default values that are baked into the image. Can be overridden at runtime.
FROM node:20-alpine
# Set defaults in image
ENV NODE_ENV=production
ENV PORT=3000
ENV LOG_LEVEL=info
# Multiple variables
ENV NODE_ENV=production \
PORT=3000 \
LOG_LEVEL=info
WORKDIR /app
COPY . .
RUN npm ci
CMD ["node", "server.js"]
At runtime, override the Dockerfile defaults:
docker run -d -e NODE_ENV=development my-app
4. ARG instruction in Dockerfile (build-time only)
Build arguments are passed at docker build time. They are NOT available at runtime.
# Declare a build arg with an optional default
ARG NODE_VERSION=20
ARG APP_VERSION
FROM node:$NODE_VERSION-alpine
ARG APP_VERSION
LABEL version=$APP_VERSION
COPY . .
RUN npm ci
CMD ["node", "server.js"]
Pass at build time:
docker build --build-arg NODE_VERSION=18 --build-arg APP_VERSION=1.2 -t my-app .
ARG vs ENV - Key Differences
| Feature | ARG | ENV |
|---|---|---|
| Available during build | ||
| Available at runtime | ||
Visible in docker inspect | No | Yes |
Overridden at docker run | No | Yes (with -e) |
Used in FROM instruction | Yes | No |
| Secure (not logged) | More secure | Visible in image metadata |
Environment Variables in Docker Compose
Method 1 - Inline in compose file
services:
app:
image: my-app
environment:
APP_ENV: production
DB_HOST: db
DB_PORT: 3306
Method 2 - List format
services:
app:
image: my-app
environment:
- APP_ENV=production
- DB_HOST=db
- DB_PORT=3306
Method 3 - Pass from shell
services:
app:
image: my-app
environment:
- APP_ENV # value taken from your shell's APP_ENV variable
- DB_PASSWORD # value taken from your shell
Method 4 - env_file in compose
services:
app:
image: my-app
env_file:
- .env
- .env.local
Method 5 - .env file (auto-loaded by Compose)
Compose automatically reads a .env file in the same directory and uses it for variable substitution in the compose file:
# .env
DB_ROOT_PASSWORD=secret
APP_PORT=8080
IMAGE_TAG=1.0
services:
app:
image: my-app:${IMAGE_TAG}
ports:
- "${APP_PORT}:80"
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
Checking Environment Variables
# Check all env vars in a running container
docker exec my-app printenv
# Check a specific variable
docker exec my-app printenv DB_HOST
# Check via inspect
docker inspect -f '{{json .Config.Env}}' my-app
# Inside the container (if you have a shell)
docker exec -it my-app bash
env
echo $DB_HOST
Best Practices
Never hardcode secrets in Dockerfiles
# BAD - password is in image history and metadata
ENV DB_PASSWORD=mysecret123
# GOOD - set it at runtime
# docker run -e DB_PASSWORD=mysecret123 my-app
Never commit .env files with secrets
# .gitignore
.env
.env.local
.env.production
Use different .env files for different environments
.env <- Default values (safe to commit, no secrets)
.env.development <- Dev values (safe to commit)
.env.production <- Production secrets (NEVER commit)
Use Docker Secrets for sensitive data (Swarm/Compose)
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Quick Reference
| Method | How |
|---|---|
| Single var at run | docker run -e KEY=value |
| Multiple vars at run | docker run -e K1=v1 -e K2=v2 |
| From .env file at run | docker run --env-file .env |
| Baked into image | ENV KEY=value in Dockerfile |
| Build-time only | ARG KEY=value in Dockerfile |
| In Compose (inline) | environment: KEY: value |
| In Compose (file) | env_file: .env |
| Compose substitution | ${VARIABLE} from .env file |
FAQ
Should I memorize every Docker command?+
No. Memorize the core workflow first: build, run, list, inspect, logs, exec, stop, remove, and clean up. Then learn specialized commands when you need them.
Is Docker only for developers?+
No. Docker is useful for system administrators, infrastructure engineers, DevOps engineers, cloud engineers, support engineers, and learners who want repeatable labs.
What should I do after reading this guide?+
Run the examples, write down what each command changes, rebuild the workflow with Docker Compose, and then add one CI/CD step that builds the image automatically.
Need help applying Docker in a real project?
Work directly with Muhammad Irfan Aslam for Docker, Linux, DevOps, CI/CD, cloud deployment, or infrastructure troubleshooting support.
Hire Me for Support