What is Docker Compose and when would you use it?
Docker Compose lets you define a multi-container app, such as a web server, database and cache, in one YAML file and start or stop all of it with one command. It sets up a shared network so services reach each other by name, and it is mainly used for local development, testing and small single-server deployments.
Explain it simply
Running one container is like cooking one dish. A real app is a full thali: a web server, a database, maybe Redis for caching. Without Compose you would type a long docker run command for each one, remember the ports, the passwords, the network and the order. Compose is the written menu card for the whole thali. You write it once in a file, and then docker compose up serves everything together.
Example
A Node.js API with PostgreSQL, in a file called compose.yaml:
services:
api:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:secret@db:5432/appdb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 3s
retries: 10
volumes:
pgdata:docker compose up -d # build if needed and start everything in the background
docker compose ps # see the status of each service
docker compose logs -f api # follow logs of one service
docker compose down # stop and remove containers and the network
docker compose down -v # same, and also delete named volumesNotice the database host in DATABASE_URL is just db, the service name.
How it works
Compose reads the YAML file and talks to the Docker engine for you. For a project it creates:
- A default network, and every service joins it. Docker's built-in DNS lets each service find the others by service name, so
apiconnects todb:5432. Only ports listed underportsare published to your laptop. - Containers for each service, built from a Dockerfile (
build) or pulled from a registry (image). - Named volumes declared at the bottom, which survive
docker compose downunless you add-v.
depends_on controls start order. On its own it only waits for the other container to start, not for the database to be ready to accept connections. Adding condition: service_healthy with a healthcheck, as above, makes Compose wait until the check passes.
Compose v2 is built into Docker as docker compose (with a space). The old docker-compose Python tool is retired, and the top-level version: key is no longer needed.
Real-world use
A new intern can clone the repo and run one command to get the API, database, Redis and a mail-catcher running locally, instead of following a two-page setup document. CI pipelines use Compose to spin up a real database for integration tests. Small projects and side projects sometimes run Compose on a single VPS in production. Large production systems that need many servers, auto-healing and rolling updates usually move to Kubernetes or a managed container service.
Common mistakes
- Using
localhostto reach another service. Inside a container,localhostis that container itself; use the service name. - Assuming
depends_onwaits until the database is ready. - Committing real passwords in
compose.yaml. Use an.envfile that is not committed, or secrets. - Running
docker compose down -vcasually and deleting the development database. - Treating Compose as a multi-server orchestrator. It runs on one Docker host.
What to say in the interview
"Docker Compose is a tool for defining and running multi-container applications from a single YAML file. I declare services, their images or build context, ports, environment variables, volumes and dependencies, and then docker compose up starts them together on a shared network where they can reach each other by service name. I use it for local development and integration tests, so the whole stack is reproducible with one command. For production at scale across many machines I would use Kubernetes instead."
Follow-up questions
- How do containers in a Compose project find each other?
- Why can the API fail on startup even with
depends_on? - How do you use different settings for development and production?
- How is Compose different from Kubernetes?
Go deeper
Read these once the basics above feel easy.
You can layer files: compose.yaml holds the shared setup, and compose.override.yaml is merged automatically for local development, for example to add a bind mount for live reloading. Profiles let you mark optional services, such as an admin UI, that only start with docker compose --profile tools up. Variables like ${POSTGRES_PASSWORD} in the YAML are filled from an .env file in the project folder.