Docker Compose
- Docker Compose is a tool for defining and running multi-container applications using a single
docker-compose.ymlfile. - Instead of running multiple
docker runcommands with flags, you declare your entire application stack (services, networks, volumes) in YAML and manage it with a singledocker compose up. - Compose is now part of Docker CLI (
docker compose- v2). The standalonedocker-composeCLI (v1) is deprecated.
Core Concepts
Section titled “Core Concepts”- Service: A container definition. Each service maps to one Docker image and runs one or more container instances.
- Network: Compose creates a default bridge network for the project. All services on it can reach each other by service name (built-in DNS).
- Volume: Named storage attached to one or more services for data persistence.
- Project: The logical grouping of everything in a
docker-compose.yml. Project name defaults to the directory name.
docker-compose.yml Structure
Section titled “docker-compose.yml Structure”# docker-compose.yml — a full application stack exampleservices:
web: image: nginx:alpine ports: - "80:80" # host:container volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro # bind mount, read-only depends_on: - app # starts after app is healthy
app: build: context: . # build from Dockerfile in current dir dockerfile: Dockerfile.prod environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb # ⚠️ Don't hardcode creds — use env_file or secrets env_file: - .env # load additional env vars from file (add to .gitignore!) restart: unless-stopped
db: image: postgres:16-alpine volumes: - db-data:/var/lib/postgresql/data # named volume for persistence environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: mydb healthcheck: test: ["CMD-SHELL", "pg_isready -U user -d mydb"] interval: 5s timeout: 5s retries: 5
volumes: db-data: # declares the named volumeKey Commands
Section titled “Key Commands”# Start all services (detached)docker compose up -d
# Start and rebuild images before startingdocker compose up -d --build
# Stop services (containers remain, volumes intact)docker compose stop
# Stop and remove containers and networks (volumes preserved by default)docker compose down
# Stop, remove containers, networks, AND named volumesdocker compose down -v
# View running servicesdocker compose ps
# Tail logs from all servicesdocker compose logs -f
# Tail logs from a specific servicedocker compose logs -f app
# Execute a command in a running servicedocker compose exec app bashdocker compose exec db psql -U user -d mydb
# Scale a service to N instancesdocker compose up -d --scale app=3
# Pull latest images for all servicesdocker compose pull
# Validate and view the merged configdocker compose configNetworking in Compose
Section titled “Networking in Compose”- Compose creates a default bridge network:
<project-name>_default. - Services can reach each other by service name - no IP addresses needed.
# In the app service, connect to the database using the service name "db"DATABASE_URL=postgres://user:pass@db:5432/mydb # "db" resolves to the db container's IP- Define custom networks for isolation between service groups:
services: frontend: networks: [public] api: networks: [public, private] db: networks: [private] # db not reachable from frontend
networks: public: private:Compose File Format Versions
Section titled “Compose File Format Versions”The version: key at the top of the file specifies the Compose file format.
[!note] The
versionfield is deprecated as of Compose Specification (2021). Modern Docker Compose (v2) uses the Compose Spec and ignores this field. Omit it from new files.
| Format | Notable Addition |
|---|---|
| v1 | No version key. Services linked with links:. |
| v2 | Added version: key, depends_on:, health checks, named volumes. |
| v3 | Added deploy: key for Swarm mode (replicas, resource limits). |
| Compose Spec | Unified spec replacing versioned formats. version field optional/ignored. |
# Modern Compose file - no version key neededservices: web: image: nginxPractical Patterns
Section titled “Practical Patterns”Environment-specific overrides
Section titled “Environment-specific overrides”# docker-compose.yml — base config# docker-compose.override.yml — auto-loaded on top (dev defaults)# docker-compose.prod.yml — explicit for production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dHealth checks with depends_on
Section titled “Health checks with depends_on”Without health checks, depends_on only waits for the container to start, not to be ready:
depends_on: db: condition: service_healthy # waits for healthcheck to passOne-off commands
Section titled “One-off commands”# Run database migrations before starting the appdocker compose run --rm app python manage.py migrate
# If migrations need to connect to an exposed port, add --service-ports# (docker compose run doesn't publish ports by default)docker compose run --rm --service-ports app python manage.py migrateWatch mode (hot reload)
Section titled “Watch mode (hot reload)”Added in Docker Compose 2.22 — automatically syncs or rebuilds when files change:
services: app: build: . develop: watch: - action: sync # copy changed files into the container without rebuild path: ./src target: /app/src - action: rebuild # rebuild image when these files change path: package.json# Start services with file watching enableddocker compose watchUseful alternative to bind mounts for development — more explicit about what triggers a sync vs a full rebuild.