Docker Compose Production Patterns

Layer a base compose file with an override for production, set resource limits, restart policies and healthcheck-aware dependencies.

Compose is not just for local dev. With a few patterns it runs small production stacks cleanly. The core idea is one base file plus environment-specific overrides.

Base + override files

Keep shared config in compose.yml and put prod-only settings (resource limits, no bind-mounted source, real restart policies) in compose.prod.yml. Compose merges them in order.

Production must-haves

  • Restart policyrestart: unless-stopped so services survive reboots.
  • Resource limits — cap memory and CPU so one service can't starve the host.
  • Health-gated startupdepends_on with condition: service_healthy.
  • Pinned images — real tags or digests, never latest.
  • No source bind mounts — ship the built image instead.

Roll it out

Deploy with both files and Compose does the merge. docker compose pull then up -d gives you a rolling-ish update on a single host.

Example

Example · yaml
# compose.prod.yml — merged on top of compose.yml
services:
  api:
    image: ghcr.io/acme/api:1.4.2
    restart: unless-stopped
    env_file: [.env.production]
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/healthz"]
      interval: 30s
      timeout: 3s
      start_period: 20s
      retries: 3
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 3s
      retries: 5

volumes:
  pgdata:

When to use it

  • A team maintains a base compose.yml for shared config and a compose.override.prod.yml that adds resource limits, restart policies, and production env vars.
  • A CD pipeline runs docker compose -f compose.yml -f compose.prod.yml up -d to merge the base and production configs at deploy time.
  • An ops engineer sets memory limits on all compose services to prevent a single runaway service from starving the host.

More examples

Base and production override files

Separates base config from production-only concerns (restarts, limits, logging) into two files merged at deploy time.

Example · yaml
# compose.yml (base)
services:
  api:
    build: .
    environment:
      NODE_ENV: production

# compose.prod.yml (override)
services:
  api:
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
    logging:
      driver: json-file
      options:
        max-size: '10m'
        max-file: '3'

Deploy with merged compose files

Merges base and production compose files, rebuilds images, starts services, and removes orphaned containers.

Example · bash
docker compose \
  -f compose.yml \
  -f compose.prod.yml \
  up -d --build --remove-orphans

Rolling update for a service

Pulls the latest api image and recreates only that service without restarting its dependencies.

Example · bash
# Pull the new image version
docker compose pull api

# Recreate only the api service with zero downtime (requires multiple replicas)
docker compose up -d --no-deps api

Discussion

  • Be the first to comment on this lesson.