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

FeatureARGENV
Available during build
Available at runtime
Visible in docker inspectNoYes
Overridden at docker runNoYes (with -e)
Used in FROM instructionYesNo
Secure (not logged)More secureVisible 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

MethodHow
Single var at rundocker run -e KEY=value
Multiple vars at rundocker run -e K1=v1 -e K2=v2
From .env file at rundocker run --env-file .env
Baked into imageENV KEY=value in Dockerfile
Build-time onlyARG 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