HxHippy

Environment Variables

Manage configuration with environment variables in Docker Compose.

Last updated: 2025-01-15

Environment Variables in Compose

Configure services with environment variables for flexible deployments.

Defining Variables

Inline Definition

services:
  api:
    environment:
      - NODE_ENV=production
      - PORT=3000
      - DEBUG=false

    # Or map syntax
    environment:
      NODE_ENV: production
      PORT: 3000
      DEBUG: "false"

From .env File

services:
  api:
    env_file:
      - .env
      - .env.local      # Overrides .env
# .env
DATABASE_URL=postgres://user:pass@db:5432/app
REDIS_URL=redis://redis:6379
API_KEY=secret123

Variable Substitution

services:
  api:
    image: myapp:${APP_VERSION:-latest}
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - API_KEY=${API_KEY}

Variable Syntax

# Required variable (error if missing)
${VARIABLE}

# Default value if unset
${VARIABLE:-default}

# Default value if unset or empty
${VARIABLE-default}

# Error with message if unset
${VARIABLE:?error message}

Environment File Priority

  1. Shell environment variables
  2. .env file in project directory
  3. env_file directive in compose
  4. Default values in compose file

Multiple Environment Files

services:
  api:
    env_file:
      - .env              # Base config
      - .env.production   # Production overrides
# .env
DATABASE_HOST=localhost
DEBUG=true

# .env.production
DATABASE_HOST=prod-db.example.com
DEBUG=false

Per-Environment Compose Files

# docker-compose.yml (base)
services:
  api:
    build: .
    environment:
      - NODE_ENV=${NODE_ENV:-development}
# docker-compose.prod.yml (override)
services:
  api:
    environment:
      - NODE_ENV=production
      - LOG_LEVEL=warn
# Development
docker compose up

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up

Secrets (Not Environment Variables)

services:
  api:
    secrets:
      - db_password
      - api_key
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt

Interpolation in Compose

services:
  api:
    image: ${REGISTRY:-docker.io}/myapp:${VERSION:-latest}
    ports:
      - "${API_PORT:-3000}:3000"
    deploy:
      replicas: ${REPLICAS:-1}

Complete Example

# docker-compose.yml
services:
  api:
    build: .
    ports:
      - "${API_PORT:-3000}:3000"
    env_file:
      - .env
    environment:
      - NODE_ENV=${NODE_ENV:-development}
      - DATABASE_URL=postgres://${DB_USER}:${DB_PASS}@db:5432/${DB_NAME}
    secrets:
      - api_secret

  db:
    image: postgres:${POSTGRES_VERSION:-16}-alpine
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
      POSTGRES_DB: ${DB_NAME}
    secrets:
      - db_password

secrets:
  api_secret:
    file: ./secrets/api.txt
  db_password:
    file: ./secrets/db.txt
# .env
NODE_ENV=production
DB_USER=appuser
DB_NAME=myapp
API_PORT=8080
POSTGRES_VERSION=16

Best Practices

  1. Never commit secrets - Add .env to .gitignore
  2. Use defaults - Provide sensible defaults with :-
  3. Validate required vars - Use :? for critical config
  4. Separate secrets - Use Docker secrets for sensitive data
  5. Document variables - Create .env.example template
beginner Docker Compose Updated 2025-01-15
  • docker compose
  • environment
  • env
  • configuration
  • secrets