Docker Compose Examples

Docker Compose lets you define and manage multi-container applications with a single YAML file. Instead of running complex docker run commands, you declare all services, networks, and volumes in docker-compose.yml and manage the whole stack with simple commands.

DockerComposeDevOpsCLI
Example Compose File
Basic web + database stack
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
A minimal but complete docker-compose.yml with an nginx web server and PostgreSQL database. depends_on ensures db starts before web. The named volume pgdata persists database data across container restarts.
Common Commands
Start all services in background
docker compose up -d
The -d flag runs containers in detached mode (background). Without it, logs stream to your terminal. Run this from the directory containing docker-compose.yml. Use docker compose ps to verify all services started.
Stop and remove containers
docker compose down
Stops and removes all containers, networks, and the default network created by up. Named volumes are preserved by default. Add -v to also remove named volumes (deletes all data — use with caution).
Rebuild images and restart
docker compose up -d --build
The --build flag forces Docker to rebuild images from Dockerfiles before starting. Use this after changing your Dockerfile or application code. Without it, Compose uses cached images even if the source has changed.
View logs from all services
docker compose logs -f
The -f flag follows (tails) the logs in real time. Without it, all historical logs are printed and the command exits. Specify a service name to filter: docker compose logs -f web.
Execute a command inside a running service
docker compose exec web sh
Opens an interactive shell inside the running web container. This is equivalent to docker exec -it but uses the service name instead of the container ID. Use bash if the container has bash installed.
Advanced Patterns
Use an .env file for configuration
# .env file:
DB_PASSWORD=supersecret
APP_PORT=3000

# docker-compose.yml:
services:
  app:
    env_file:
      - .env
    ports:
      - "${APP_PORT}:3000"
The env_file directive loads variables from a file into the container. Variables in .env are also available for interpolation in the compose file itself with ${VAR} syntax. Never commit .env files with secrets to version control.
Add a health check to a service
services:
  web:
    image: myapp
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
Health checks let Compose know when a container is truly ready to accept traffic, not just running. Other services using depends_on: service: condition: service_healthy will wait until the health check passes.
Scale a service horizontally
docker compose up -d --scale web=3
The --scale flag runs multiple instances of a service. Useful for testing load balancing locally. Note: port mapping must use a range (e.g., "8080-8082:80") or omit host port binding when scaling.

How to Use

  1. Create a docker-compose.yml file in your project root.
  2. Define each service under the services: key with image, ports, and environment.
  3. Run docker compose up -d to start all services in the background.
  4. Use docker compose logs -f to monitor logs and docker compose down to stop.
  5. Use docker compose up -d --build after code changes to rebuild and restart.

Frequently Asked Questions

What is the difference between docker-compose and docker compose?

docker-compose (with hyphen) is the older standalone Python-based tool (v1). docker compose (as a subcommand) is the newer Go-based plugin integrated into the Docker CLI (v2). They are functionally similar but v2 is faster. Modern Docker Desktop includes v2 by default.

How do I persist data between container restarts?

Use named volumes (defined in the top-level volumes: section) or bind mounts (host directory paths). Named volumes are managed by Docker and survive docker compose down. They are deleted only when you explicitly remove them with docker compose down -v.

How do services communicate with each other in Compose?

Compose automatically creates a shared network for all services in the same file. Services can reach each other using the service name as the hostname. For example, the web service can connect to the database at hostname db on its exposed port.

Related Tools