📝 Docker

Environment Variables in Docker

P
Author
Pyland
📅
Published
30.06.2026
⏱️
Reading time
2 min
👁️
Views
69
🌿
Level
Medium

Environment variables are the standard way to configure containers. They let you use a single image across different environments (dev, staging, prod) without rebuilding.

ENV in Dockerfile: Default Values

ENV sets variables that are available both during the build and at container runtime. These act as defaults.

FROM python:3.12-slim

# Default values
ENV APP_ENV=production
ENV PORT=8000
ENV LOG_LEVEL=info
ENV DEBUG=false

WORKDIR /app
COPY . .

CMD ["python", "main.py"]

In application code:

import os

port = int(os.environ.get("PORT", 8000))
debug = os.environ.get("DEBUG", "false").lower() == "true"
log_level = os.environ.get("LOG_LEVEL", "info")

Values set with ENV in the Dockerfile are defaults and can be overridden at runtime.

The -e Flag: Variables at Runtime

# Single variable
docker run -e DEBUG=true my-app

# Multiple variables
docker run \
  -e DEBUG=true \
  -e PORT=9000 \
  -e DATABASE_URL=postgresql://localhost/mydb \
  my-app

# Pass a variable from the host environment
export API_KEY=secret123
docker run -e API_KEY my-app       # value is taken from the host

Variables passed with -e override any ENV instructions in the Dockerfile.

The –env-file Flag: Variables from a File

When you have many variables, storing them in a file is more convenient:

# dev.env
DEBUG=true
PORT=8000
DATABASE_URL=postgresql://localhost/devdb
LOG_LEVEL=debug
REDIS_URL=redis://localhost:6379
docker run --env-file dev.env my-app
docker run --env-file prod.env my-app

File format: one variable per line, KEY=VALUE. Lines starting with # are comments.

environment: in docker-compose.yml

services:
  web:
    build: .
    environment:
      # Explicit values
      DEBUG: "false"
      PORT: "8000"
      LOG_LEVEL: info
      # From the host environment (no value given)
      SECRET_KEY:
      API_KEY:

  worker:
    build: .
    environment:
      - QUEUE_NAME=tasks
      - CONCURRENCY=4

Both syntaxes (key: value and - KEY=VALUE) are equivalent.

.env File in Docker Compose

Docker Compose automatically loads a .env file from the same directory as docker-compose.yml. Values from .env are substituted into docker-compose.yml via ${VAR}.

# .env
POSTGRES_PASSWORD=mysecretpass
POSTGRES_USER=myuser
IMAGE_TAG=1.2.3
APP_PORT=8000
services:
  web:
    image: my-app:${IMAGE_TAG}
    ports:
      - "${APP_PORT}:8000"
    environment:
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/mydb

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
# Verify variable substitution
docker compose config

You can set a default value with ${VAR:-default}:

image: my-app:${IMAGE_TAG:-latest}

Never Bake Secrets into an Image

A common mistake is hardcoding a secret directly in the Dockerfile:

# BAD: the secret ends up in an image layer and in git
ENV API_KEY=super_secret_key_12345
RUN curl -H "Authorization: ${API_KEY}" https://api.example.com/setup

Even if you unset the variable in a later layer, it stays in the image history and is visible via docker history.

The correct approach:

# GOOD: no secrets in the Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY . .
CMD ["python", "main.py"]
# Secret is passed at runtime and never baked into the image
docker run -e API_KEY=secret my-app

.gitignore and .dockerignore

# .gitignore — do not commit to git
.env
.env.local
.env.production
*.env

# .dockerignore — do not copy into the image
.env
.env.*

Variable Priority (highest to lowest)

1. -e flag / environment: in compose
2. --env-file / env_file: in compose
3. .env file (Docker Compose only)
4. ENV in Dockerfile

Example: Configuration for Different Environments

# .env.dev
DATABASE_URL=postgresql://localhost/devdb
DEBUG=true
LOG_LEVEL=debug

# .env.prod
DATABASE_URL=postgresql://prod-server/mydb
DEBUG=false
LOG_LEVEL=warning
# Start in dev
docker compose --env-file .env.dev up

# Start in prod
docker compose --env-file .env.prod up

Your reaction to the article

💬 Comments (0)

🔐 Sign in to leave a comment
🚪 Login
💭

No comments yet

Be the first to share your opinion about this article!

🔗 Similar

Similar articles

Continue learning with these materials

📝

Deploying FastAPI with Docker

Railway will also automatically detect a Dockerfile if one is present.

📅 30.06.2026 👁️ 77
📝

Multi-stage Builds: Shrinking Your Docker Image

A large image means slow downloads, more disk usage, and a bigger attack surface. Multi-stage...

📅 30.06.2026 👁️ 77
📝

Docker Compose: Advanced Features

A basic docker-compose.yml is just the starting point. Production workloads need healthchecks, profiles, override files,...

📅 30.06.2026 👁️ 71

Did you like the article?

Subscribe to our updates and receive new articles first. Grow with PyLand!