Docker Compose overview
June 20, 2026Docker Compose runs multi-container applications from a single YAML file. One command can start an API, a database, a message broker, and supporting tools for local development - without installing each service on the host machine.
This post covers Compose concepts and commands. For ready-made stacks, see the service-specific posts linked at the end (Postgres/Redis, RabbitMQ, MongoDB, Kafka, DynamoDB/SQS).
Prerequisites
- Docker Engine installed
- Compose V2 - use
docker compose(with a space). Current Docker Desktop includes it; no separate Compose install is required.
Mental model
- Project - the folder that contains
docker-compose.yml. The project name defaults to the directory name and prefixes container names. - Services - named containers defined in the file (
api,redis,postgres). Each service maps to one image or build context. - Network - Compose creates a default network so services resolve each other by name. From the
apicontainer, Redis is reachable atredis:6379, notlocalhost:6379. - Volumes - named or bind mounts for data that survives
docker compose down(unless you pass-v).
Minimal compose file
A two-service stack: a Node API and Redis. No top-level version: key - it is deprecated in the current Compose specification.
services:api:build: .ports:- 3000:3000environment:REDIS_URL: redis://redis:6379depends_on:- redisredis:image: redis:alpinevolumes:- redis-data:/datavolumes:redis-data:
Run docker compose up --build from the directory that contains this file.
Core concepts
Ports - map host ports to container ports as host:container:
ports:- 3000:3000
Environment - inline variables or an env file:
environment:REDIS_URL: redis://redis:6379env_file:- .env
Volumes - named volumes are managed by Docker (good for database data). Bind mounts map a host path into the container (good for live code reload during development):
volumes:- redis-data:/data # named- ./src:/app/src:ro # bind mount
Networks - services on the default network can reach each other by service name. Custom networks isolate groups of services (see the Postgres and Redis post for a multi-network example).
depends_on - controls startup order. It does not wait for the dependency to be ready; add a healthcheck or retry logic in the app when you need readiness.
restart - policies like on-failure:3 or unless-stopped keep containers running after crashes or host reboots.
healthcheck - optional probe so Compose and other services know when a container is ready:
healthcheck:test: ['CMD', 'redis-cli', 'ping']interval: 5stimeout: 3sretries: 5
Commands
| Command | Purpose |
|---|---|
docker compose up | Start services (foreground, logs in terminal) |
docker compose up -d | Start in detached mode |
docker compose up --build | Rebuild images before starting |
docker compose down | Stop and remove containers |
docker compose down -v | Also remove named volumes |
docker compose ps | List running services |
docker compose logs -f api | Follow logs for one service |
docker compose exec api sh | Open a shell in a running container |
docker compose pull | Pull latest images |
When to use what
| Tool | Best for |
|---|---|
docker run | One-off containers, quick image tests |
| Docker Compose | Local multi-service stacks, dev databases and queues |
| Kubernetes | Production orchestration, scaling, rolling deploys |
Service-specific setups
- Postgres and Redis containers with Docker Compose - databases with Pgweb and Redis Commander
- RabbitMQ container with Docker Compose - message broker with management UI
- MongoDB containers with Docker Compose - MongoDB with Mongo Express
- Kafka containers with Docker Compose - KRaft-mode Kafka with Kafka UI
- DynamoDB and SQS containers with Docker Compose - DynamoDB Local and ElasticMQ
Demo
Runnable files for this post live in the docker-compose-overview-demo folder. Get access via code demos.