In the Docker course you ran individual containers with docker run. That works perfectly for a single, isolated container. But real production applications are never just one container — they're a system of cooperating services.
A typical three-tier web application looks like this:
To run this stack manually with bare docker run commands:
Problems with this approach:
- New developer joins → reads the README, misses one flag, gets a cryptic error at midnight
- You rename a container → must update every downstream reference manually
- Postgres hasn't fully initialized when the API starts →
ECONNREFUSEDon boot - No
--restartflags → containers die on reboot and stay dead - Impossible to manage across multiple environments (dev, staging, prod) consistently
Docker Compose: The Solution
Docker Compose lets you describe your entire application stack — all services, networks, volumes, environment variables, and dependencies — in a single declarative YAML file. Then one command manages the whole thing:
The same three-tier stack from above becomes:
What you gain:
- One file checked into version control — everyone on the team runs the same stack
- Service discovery by name —
apireaches the database at hostnamedbautomatically - Dependency ordering —
apiwon't start untildbpasses its health check - Reproducible everywhere — dev laptop, CI, staging server, production VPS
How Compose Works Under the Hood
Compose reads your YAML, computes a dependency graph from depends_on, creates the network and volumes (idempotent — safe to re-run), then starts containers in the correct order, waiting for health checks where configured.
docker compose vs docker-compose
Compose v2 is the current standard as of Docker Engine 20.10+. Always use docker compose (with a space). The hyphenated version (docker-compose) is a legacy Python binary that is no longer maintained.
What Docker Compose Is NOT
Compose is excellent for development and single-server production deployments. But it has hard architectural limits:
| Capability | Docker Compose | Kubernetes |
|---|---|---|
| Multi-server | ❌ Single host only | ✅ Cluster of servers |
| Auto-scaling | ❌ Manual only | ✅ HPA by CPU/memory |
| Cross-node self-healing | ❌ Single node restart only | ✅ Pods reschedule across nodes |
| Rolling zero-downtime updates | ⚠️ Brief downtime | ✅ Guaranteed zero downtime |
| Load balancing across nodes | ❌ | ✅ |
| Learning curve | ✅ Low (< 1 day) | ❌ Steep (weeks) |
| Right for | Dev + small prod | Large-scale production |
For a single VPS hosting a startup's backend, Docker Compose is the right choice. When you need multiple servers, auto-scaling, or zero-downtime at scale — that's when you graduate to K3s or Kubernetes.
Summary
- Real applications need multiple containers (API, database, cache) that must communicate, start in the right order, and restart reliably
- Managing this with bare
docker runcommands is error-prone, hard to share, and not reproducible docker-compose.ymldeclares the entire stack — services, networks, volumes, dependencies — in one file checked into version controldocker compose up -dstarts everything;docker compose downstops everything cleanly- Always use
docker compose(v2, space) — the olddocker-compose(hyphen) is deprecated - Compose is ideal for development and single-server production; Kubernetes handles multi-server scale
In the next lesson, you will dissect every section of the docker-compose.yml file in detail.