█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/DevOps and Infrastructure/Docker and Containerization/Docker Compose
50 minIntermediate

Docker Compose

After this lesson, you will be able to: Use Docker Compose to define multi-container applications: services, networks, volumes, environment variables, depends_on.

Compose lets you describe an entire stack (app + DB + cache + reverse proxy) in one YAML file and bring it up with one command. The default for dev environments; common for small production deploys.

Prerequisites:Writing Dockerfiles

A docker-compose.yml that runs a real stack

Drop in your project root. Run `docker compose up -d`.

tsx
# docker-compose.yml
services:
web:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:app@db:5432/app
REDIS_URL: redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
restart: unless-stopped
volumes:
pgdata:

Compose commands

Memorise these.

tsx
docker compose up # build + start, foreground
docker compose up -d # detached
docker compose up --build # force rebuild
docker compose down # stop + remove containers + networks
docker compose down -v # also remove volumes (DESTRUCTIVE)
docker compose ps # status
docker compose logs -f web # tail logs of one service
docker compose exec web bash # shell into the web service
docker compose restart web # restart one service

Networks: how services talk to each other

Compose puts every service on a default network. Services reach each other by SERVICE NAME, not IP. In the file above, `web` connects to the database with the URL `postgres://app:app@db:5432/app`, `db` is the service name, resolved to the container's IP automatically. If you need multiple networks (e.g. a public + private network), declare them under top-level `networks:` and attach services explicitly.

Volumes: persistent data across restarts

Without a volume, container data is lost on `docker compose down`. Database = lost. Named volumes (declared under top-level `volumes:`) survive container removal. Always use them for stateful services. Bind mounts (host path) are great for dev (live-edit code into a container) but tricky in production (host file permissions).

depends_on: not really a dependency

Naively, `depends_on: [db]` makes the web service WAIT for db to start. But Docker only waits for db's PROCESS to start, not for postgres to be ready to accept connections. Use `condition: service_healthy` + a healthcheck on the dependency (see the YAML above). That waits until postgres responds to pg_isready before starting web. Skipping the healthcheck means web sometimes crashes on first boot because db isn't ready.

Common mistakes only experienced engineers avoid

Hardcoding secrets in docker-compose.yml. Use `.env` files (auto-loaded by compose) or `secret:` declarations. Skipping healthchecks on dependencies. Boot-order races bite. Using bind mounts for postgres data in production. Permission and performance problems on Mac/Windows. `docker compose down -v` in production by accident. Wipes data volumes. Aliasing is dangerous; train your fingers. Letting compose be the deploy tool in production. Compose works for small single-host deploys; for anything else, use Kubernetes or a managed container platform.

Quick Check

Your `web` service crashes at first boot with 'connection refused' to `db`. The db container is running. What's the FIRST fix?

Pick the correct mitigation.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Writing Dockerfiles
Back to Docker and Containerization
Docker Networking→