Docker Compose Cheatsheet

The complete quick reference for docker-compose.yml syntax and docker compose CLI commands. Covers every key you will use in production, plus real-world example files you can copy and adapt.

Top-Level Keys

Every docker-compose.yml file is built from these root-level keys. The services key is the only one that is required.

KeyDescription
versionCompose file format version (deprecated in Compose V2 — included for legacy compatibility).
servicesDefine the containers (services) that make up your application.
volumesDeclare named volumes that can be shared across services.
networksCreate custom networks for inter-service communication.
configsDefine configuration objects that can be mounted into services.
secretsDeclare sensitive data that is made available to services at runtime.

Service Configuration

Keys available inside each service definition. These control how the container is built, configured, and connected.

KeyDescription
imageThe Docker image to use, e.g. postgres:16-alpine.
buildBuild context and Dockerfile path. Accepts a string or object with context, dockerfile, args, target.
container_nameCustom name for the container (default is project_service_index).
commandOverride the default CMD of the image.
entrypointOverride the default ENTRYPOINT of the image.
portsMap host ports to container ports. Short syntax: "8080:80". Long syntax supported.
exposeExpose ports to other services on the network without publishing to the host.
environmentSet environment variables as a map or list: KEY=value.
env_fileLoad environment variables from one or more .env files.
volumesMount host paths or named volumes. Short: ./data:/var/lib/data. Long syntax supported.
networksAttach the service to one or more networks.
depends_onExpress service startup order. Use condition: service_healthy for health-gated deps.
restartRestart policy: no | always | on-failure | unless-stopped.
healthcheckDefine a health check: test, interval, timeout, retries, start_period.
deploySwarm/resource configuration: replicas, resources (limits/reservations), placement, update_config.
labelsAdd metadata labels to the container.
loggingConfigure the logging driver and options.
working_dirSet the working directory inside the container.
userRun the container process as this user (uid:gid).
stdin_open / ttyKeep STDIN open (stdin_open: true) and allocate a TTY (tty: true) for interactive use.
profilesAssign the service to one or more profiles so it only starts when that profile is active.
platformTarget platform, e.g. linux/amd64 or linux/arm64.
shm_sizeSize of /dev/shm, e.g. 256m.
cap_add / cap_dropAdd or drop Linux capabilities.
privilegedRun the container in privileged mode (full host access).
extra_hostsAdd entries to /etc/hosts inside the container.
dnsCustom DNS servers for the container.
tmpfsMount a temporary filesystem inside the container.
ulimitsSet container ulimits (nofile, nproc, etc.).

Healthcheck

Health checks let Compose wait until a service is actually ready before starting dependent services. Combine with depends_on: condition: service_healthy.

KeyDescription
testCommand to run. Use ["CMD", "curl", "-f", "http://localhost"] or CMD-SHELL string.
intervalTime between checks, e.g. 30s. Default 30s.
timeoutMax time for a single check, e.g. 10s. Default 30s.
retriesConsecutive failures before marking unhealthy. Default 3.
start_periodGrace period before checks count, e.g. 40s. Default 0s.
start_intervalInterval during start_period (Compose V2.22+). Default same as interval.

Volumes

Named volumes declared under the top-level volumes:key persist data beyond the container lifecycle. Bind mounts (host paths) are specified directly in the service's volumes: list.

KeyDescription
driverVolume driver to use (default: local).
driver_optsDriver-specific options as key-value pairs.
externalIf true, the volume must already exist (not created by Compose).
nameCustom name for the volume on the Docker host.
labelsMetadata labels for the volume.

Volume Mount Syntax

  • named_vol:/container/path — named volume
  • ./host/path:/container/path — bind mount (relative)
  • /abs/path:/container/path:ro — read-only bind mount
  • type: volume, source: mydata, target: /data — long syntax

Networks

By default Compose creates a single network for your project. Custom networks let you isolate services and control which containers can talk to each other.

KeyDescription
driverNetwork driver: bridge (default), host, overlay, macvlan, none.
driver_optsDriver-specific options.
externalIf true, the network must already exist.
internalIf true, restrict external access to the network.
ipamIP Address Management: driver, config (subnet, gateway).
nameCustom name for the network.
attachableAllow standalone containers to attach to this network (overlay only).

Deploy & Resources

The deploy key controls replica count, resource limits, rolling update strategy, and placement. Originally Swarm-only, many fields are now respected by docker compose up in Compose V2.

KeyDescription
replicasNumber of container replicas to run.
resources.limitsCPU and memory limits, e.g. cpus: '0.5', memory: 512M.
resources.reservationsGuaranteed CPU and memory reservations.
restart_policyCondition, delay, max_attempts, window for restarts.
update_configRolling update settings: parallelism, delay, failure_action, order.
rollback_configSettings for automatic rollback on update failure.
placement.constraintsPlacement constraints, e.g. node.role == manager.

CLI Commands

All docker compose (V2) commands. The legacy docker-compose (hyphenated) syntax works the same way.

CommandDescription
docker compose upCreate and start all services defined in the compose file.
docker compose up -dStart services in detached (background) mode.
docker compose up --buildRebuild images before starting services.
docker compose up --force-recreateRecreate containers even if config has not changed.
docker compose up --scale web=3Start with 3 replicas of the web service.
docker compose downStop and remove containers, networks created by up.
docker compose down -vAlso remove named volumes declared in the compose file.
docker compose down --rmi allAlso remove all images used by services.
docker compose buildBuild or rebuild service images.
docker compose build --no-cacheBuild without using cache layers.
docker compose pullPull the latest images for all services.
docker compose pushPush service images to a registry.
docker compose psList running containers for the project.
docker compose ps -aList all containers (including stopped).
docker compose logsView output logs from all services.
docker compose logs -fFollow (tail) logs in real time.
docker compose logs webView logs for a specific service.
docker compose exec web shOpen an interactive shell in a running service container.
docker compose run web bashRun a one-off command in a new container for the service.
docker compose stopStop running services without removing containers.
docker compose startStart previously stopped services.
docker compose restartRestart all services.
docker compose pausePause all running services.
docker compose unpauseUnpause paused services.
docker compose topDisplay running processes for each service.
docker compose configValidate and display the resolved compose file.
docker compose config --servicesList service names defined in the compose file.
docker compose cp web:/app/log.txt ./log.txtCopy files between a service container and the host.
docker compose watchWatch for file changes and sync/rebuild automatically (Compose Watch).
docker compose eventsStream real-time events from containers.
docker compose port web 80Print the public port mapped to a service's container port.

Example Compose Files

Copy these production-ready examples and adapt them to your project. Each demonstrates common patterns: health checks, named volumes, multi-network isolation, and resource limits.

Web App + PostgreSQL

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  pgdata:

Full Stack: Frontend + API + Postgres + Redis

services:
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      NEXT_PUBLIC_API_URL: http://localhost:4000
    depends_on:
      - api

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    ports:
      - "4000:4000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/myapp
      REDIS_URL: redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  pgdata:

Multi-Service with RabbitMQ, Nginx Reverse Proxy & Custom Networks

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/certs:/etc/nginx/certs:ro
    depends_on:
      - app1
      - app2
    networks:
      - frontend

  app1:
    build: ./services/app1
    expose:
      - "8001"
    environment:
      - APP_NAME=service-one
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: "0.5"
          memory: 256M
    networks:
      - frontend
      - backend

  app2:
    build: ./services/app2
    expose:
      - "8002"
    environment:
      - APP_NAME=service-two
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: "0.5"
          memory: 256M
    networks:
      - frontend
      - backend

  worker:
    build: ./services/worker
    environment:
      RABBITMQ_URL: amqp://rabbit:5672
    depends_on:
      rabbit:
        condition: service_healthy
    deploy:
      replicas: 3
    networks:
      - backend

  rabbit:
    image: rabbitmq:3-management-alpine
    ports:
      - "15672:15672"
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_running"]
      interval: 30s
      timeout: 10s
      retries: 5
    networks:
      - backend

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: multi
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend

networks:
  frontend:
  backend:

volumes:
  pgdata:

Development Override (docker-compose.override.yml)

# docker-compose.override.yml — auto-merged with docker-compose.yml
services:
  web:
    build:
      context: .
      target: development
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      NODE_ENV: development
      DEBUG: "true"
    ports:
      - "9229:9229"   # Node.js debugger
    command: npm run dev

  db:
    ports:
      - "5432:5432"   # Expose DB to host for local tools

Tips & Best Practices

Use .env Files

Store secrets and configuration in .env files and reference them with env_file: or variable substitution $${VAR}. Never hard-code secrets in the compose file.

Pin Image Tags

Always specify an explicit tag like postgres:16-alpine instead of postgres:latest. This ensures reproducible builds and prevents surprise breakages.

Health-Gated Dependencies

Use depends_on: condition: service_healthy instead of bare depends_on. This ensures a database is actually accepting connections before your app tries to connect.

Override Files for Dev

Create docker-compose.override.yml for development-only settings (hot reload, exposed ports, debug mode). Compose merges it automatically.

Related Resources