Skip to content

How to Use Docker Compose

Key idea:

Docker Compose — tool for defining + running multi-container apps via a single YAML file. Convenient for local dev (app + DB + Redis + nginx) and small production deployments. Rewritten as Compose v2 in 2024 (Go, integrated into Docker CLI). Commands: docker compose up, down, logs, exec. For production + scale — migrate to Kubernetes or Docker Swarm.

Below: step-by-step, working examples, common pitfalls, FAQ.

Step-by-Step Setup

  1. Install Docker Desktop (macOS/Windows) or Docker Engine + Compose v2 (Linux)
  2. Create docker-compose.yml at project root
  3. Define services: app, db, cache. Each — image or build path
  4. Volumes for persistence: volumes: { pg_data: {} }, - pg_data:/var/lib/postgresql
  5. Networks (default created): services reachable via hostname = service name
  6. docker compose up -d — start in background. logs -f — tail logs
  7. Env files: .env loaded automatically, or env_file: .env.prod
  8. Healthchecks + depends_on for correct startup order

Working Examples

ScenarioConfig
Basic web + DBservices: app: build: . ports: ["3000:3000"] env_file: .env depends_on: db: { condition: service_healthy } db: image: postgres:16-alpine volumes: - pg_data:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: ${DB_PASS} healthcheck: test: ["CMD", "pg_isready"] interval: 5s volumes: pg_data:
Full stack: app + DB + Redis + nginxservices: nginx: image: nginx:alpine ports: ["80:80"] volumes: [./nginx.conf:/etc/nginx/nginx.conf:ro] depends_on: [app] app: build: . environment: - DATABASE_URL=postgres://app:pass@db:5432/mydb - REDIS_URL=redis://cache:6379 depends_on: [db, cache] db: image: postgres:16 volumes: [pg_data:/var/lib/postgresql/data] cache: image: redis:7-alpine volumes: pg_data:
Scale horizontallydocker compose up -d --scale app=5 # 5 instances of app # Nginx upstream for load balancing between them
Override for dev vs prod# docker-compose.override.yml (dev) services: app: volumes: [.:/app] # hot reload via code mount command: npm run dev # docker-compose.prod.yml services: app: build: . command: npm run start # Use: docker compose -f docker-compose.yml -f docker-compose.prod.yml up
Exec command in running containerdocker compose exec app bash docker compose exec db psql -U app -d mydb

Common Pitfalls

  • depends_on without condition: healthy → app starts before DB ready → crash. Always healthchecks
  • Volume permissions: Postgres needs uid 999 owning /var/lib/postgresql. On mounted host volume — need chown
  • .env passwords in git — plain text. Use .gitignore + .env.example template
  • Compose v1 (docker-compose) deprecated. V2 — docker compose (space)
  • Not for production > 1 server. For multi-host — Docker Swarm or K8s

Learn more

Frequently Asked Questions

Docker Compose vs Kubernetes?

Compose: single host, dev, small prod. K8s: multi-host, auto-scaling, HA. Migration threshold: >3 services + >1 host + need auto-scaling = K8s.

Networking?

Services in same compose file automatically in shared network. Access via service name (hostname). External: expose ports via <code>ports:</code>.

Can I use Docker Compose in prod?

For small apps (side projects, internal tools) — yes. For serious business — keep dev-only, migrate to K8s for prod.

Alternative — Podman Compose?

Podman — daemonless Docker-compatible. Podman Compose — works with docker-compose.yml. For rootless Linux — preferable.