Docker Full Tutorial — Part 6: Docker Compose

By Suraj Ahir 2025-11-21 11 min read

← Part 5Docker Tutorial · Part 6 of 12Part 7 →
Docker Full Tutorial — Part 6: Docker Compose

Running one Docker container with docker run works fine. Running five containers — a web app, an API, a database, a cache, and a background worker — with five docker run commands, each with the right environment variables, volume mounts, network connections, and port mappings — is a nightmare. You need 15 terminal tabs and a notepad to remember all the flags.

Docker Compose solves this. You write one docker-compose.yml file that describes your entire application stack. Then it is just docker compose up to start everything and docker compose down to stop it. One file, two commands, your entire development environment.

Your First Docker Compose File

docker-compose.yml — Web app + PostgreSQL + Redis
version: '3.8'

services:
  app:
    build: .                      # Build from Dockerfile in current directory
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DB_HOST=postgres
      - DB_PASSWORD=devpassword
      - REDIS_HOST=redis
    volumes:
      - ./src:/app/src             # Bind mount for hot reload
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - app-network

  postgres:
    image: postgres:15
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: devpassword
      POSTGRES_DB: myapp
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    networks:
      - app-network

volumes:
  postgres-data:

networks:
  app-network:
    driver: bridge

Essential Docker Compose Commands

Daily Compose commands
# Start all services (build images if needed)
docker compose up

# Start in background (detached)
docker compose up -d

# Force rebuild all images
docker compose up --build

# Start only specific services
docker compose up app postgres

# View logs from all services
docker compose logs

# Follow logs from specific service
docker compose logs -f app

# Stop all containers (keeps data)
docker compose stop

# Stop and remove containers, networks (keeps volumes)
docker compose down

# Stop, remove containers, networks, AND volumes (destroys data)
docker compose down -v

# Run a one-off command in a service
docker compose exec app bash
docker compose run --rm app npm run migrate

# Scale a service (run 3 copies)
docker compose up --scale app=3

# See status of services
docker compose ps

Environment Variables in Compose

Using .env file with Docker Compose
# .env file (never commit to Git)
POSTGRES_PASSWORD=strongpassword
NODE_ENV=development
API_KEY=secret123
# docker-compose.yml references .env automatically
services:
  app:
    environment:
      - NODE_ENV=${NODE_ENV}
      - API_KEY=${API_KEY}
  postgres:
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

Multiple Compose Files for Environments

Override file pattern
# docker-compose.yml — base config (shared)
# docker-compose.override.yml — automatically applied in dev
# docker-compose.prod.yml — for production

# Development (uses base + override automatically)
docker compose up

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up

In Part 7, we cover Docker registries — how to push images to Docker Hub and private registries, manage image tags and versions, and set up proper image naming conventions for CI/CD pipelines.

Frequently Asked Questions

What is Docker Compose and when should I use it?

Docker Compose is a tool for defining and running multi-container Docker applications. You describe all your services, networks, and volumes in a single docker-compose.yml file, then start everything with docker compose up. Use it whenever your application has more than one container — a web app + database + cache is the classic example.

What is the difference between docker-compose.yml and Dockerfile?

A Dockerfile defines how to build a single container image — the base image, dependencies, code, and startup command. A docker-compose.yml defines how multiple containers run together — which images to use, which ports to expose, how they connect, what volumes to mount, and what environment variables each container gets. Compose uses Dockerfiles to build images.

How do I run Docker Compose in the background?

Use docker compose up -d (detached mode). The -d flag runs all containers in the background. Use docker compose logs to see their output. Use docker compose down to stop and remove all containers. Use docker compose ps to see which containers are running.

Does Docker Compose create its own network?

Yes. By default, Docker Compose creates a single network for your entire application and connects all services to it. Services can reach each other by their service name as a DNS hostname. You can define custom networks in the compose file to isolate services from each other more precisely.

What is the difference between docker compose up and docker compose start?

docker compose up creates and starts all containers from scratch (or recreates them if the compose file changed). docker compose start only starts existing stopped containers without recreating them. For daily development, use docker compose up. Use start only after explicitly stopping with docker compose stop.

Key takeaways

Continue reading
Part 7 — Registries and Image Management
Where your images actually live.
Suraj Ahir — author of SRJahir Tech

Written by

Suraj Ahir

Cloud & DevOps engineer running four live production services on my own AWS infrastructure. I write everything on this site myself — no ghostwriters, no AI filler.

← Part 5Docker Tutorial · Part 6 of 12Part 7 →
← Back to Blog
Disclaimer: This content is for educational purposes only. SRJahir Tech does not guarantee any specific outcome, job placement, or exam result.