DEV Community

Cover image for Docker Compose Complete Guide
Aditya Kumar Gupta
Aditya Kumar Gupta

Posted on

Docker Compose Complete Guide

What is Docker Compose?

Docker Compose is a tool used to define and manage multiple Docker containers using a single YAML file.

Instead of running multiple docker commands manually, Docker Compose allows you to define all services in one configuration file.

Without Compose:

docker run postgres
docker run redis
docker run backend
docker run frontend
Enter fullscreen mode Exit fullscreen mode

With Compose:

docker compose up
Enter fullscreen mode Exit fullscreen mode

Everything starts automatically.


Why Do We Need Docker Compose?

Modern applications rarely consist of a single container.

A typical application may contain:

Service Purpose
Frontend React / Next.js
Backend Node.js / Express
Database PostgreSQL
Cache Redis
Reverse Proxy Nginx

Managing these individually becomes difficult.

Docker Compose solves this problem.


Docker Compose Workflow

compose.yml
      ↓
docker compose up
      ↓
Network Creation
      ↓
Volume Creation
      ↓
Container Creation
      ↓
Application Running
Enter fullscreen mode Exit fullscreen mode

Compose automatically creates:

  • Containers
  • Networks
  • Volumes
  • Service communication

Basic Docker Compose File

services:
  app:
    build: .

  db:
    image: postgres:16
Enter fullscreen mode Exit fullscreen mode

This starts:

  • One application container
  • One PostgreSQL container

Services

Services are the most important concept in Docker Compose.

Each service represents a container.

services:
  frontend:
    build: ./frontend

  backend:
    build: ./backend

  postgres:
    image: postgres:16
Enter fullscreen mode Exit fullscreen mode

Three services create three containers.


Build

Used when Docker should build an image using a Dockerfile.

services:
  backend:
    build: .
Enter fullscreen mode Exit fullscreen mode

Equivalent command:

docker build .
Enter fullscreen mode Exit fullscreen mode

Custom path:

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile.prod
Enter fullscreen mode Exit fullscreen mode

Image

Used when Docker should pull an image from Docker Hub.

services:
  postgres:
    image: postgres:16
Enter fullscreen mode Exit fullscreen mode

Examples:

image: redis:7

image: nginx:latest

image: mongo:7
Enter fullscreen mode Exit fullscreen mode

Build vs Image

Feature Build Image
Uses Dockerfile Yes No
Builds Locally Yes No
Pulls From Registry No Yes
Used For Custom Apps Yes Yes

Interview Question:

When should you use build instead of image?

Answer

Use build when creating your own application image. Use image when using pre-built images from Docker Hub.


Container Name

Provides a custom container name.

services:
  backend:
    container_name: backend-app
Enter fullscreen mode Exit fullscreen mode

Without this:

project_backend_1
Enter fullscreen mode Exit fullscreen mode

With this:

backend-app
Enter fullscreen mode Exit fullscreen mode

Ports

Maps host ports to container ports.

ports:
  - "3000:3000"
Enter fullscreen mode Exit fullscreen mode

Format:

HOST:CONTAINER
Enter fullscreen mode Exit fullscreen mode

Example:

ports:
  - "8080:3000"
Enter fullscreen mode Exit fullscreen mode

Request:

localhost:8080
Enter fullscreen mode Exit fullscreen mode

Container receives:

3000
Enter fullscreen mode Exit fullscreen mode

Interview Question:

What is the format of port mapping?

Answer

HOST_PORT


Environment Variables

Pass runtime variables.

environment:
  NODE_ENV: production
  PORT: 3000
Enter fullscreen mode Exit fullscreen mode

Example:

services:
  backend:
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/app
Enter fullscreen mode Exit fullscreen mode

Access:

process.env.DATABASE_URL
Enter fullscreen mode Exit fullscreen mode

Env File

Store variables in a separate file.

.env

DATABASE_URL=mydb
PORT=3000
Enter fullscreen mode Exit fullscreen mode

Compose:

env_file:
  - .env
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Cleaner configuration
  • Easier secret management

Volumes

Volumes persist data.

volumes:
  - postgres-data:/var/lib/postgresql/data
Enter fullscreen mode Exit fullscreen mode

Without volumes:

Container Deleted
      ↓
Data Deleted
Enter fullscreen mode Exit fullscreen mode

With volumes:

Container Deleted
      ↓
Data Preserved
Enter fullscreen mode Exit fullscreen mode

Common use cases:

  • PostgreSQL
  • MySQL
  • MongoDB
  • File uploads

Named Volumes

services:
  postgres:
    image: postgres:16
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

Docker manages storage automatically.


Bind Mounts

Map local folders into containers.

volumes:
  - .:/app
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Live code updates
  • Faster development

Common for Next.js and Node.js projects.


Networks

Compose automatically creates a network.

Example:

services:
  backend:
  postgres:
Enter fullscreen mode Exit fullscreen mode

Backend can connect to database using:

postgres
Enter fullscreen mode Exit fullscreen mode

instead of:

localhost
Enter fullscreen mode Exit fullscreen mode

Connection string:

DATABASE_URL=postgresql://user:pass@postgres:5432/db
Enter fullscreen mode Exit fullscreen mode

Interview Question:

How do containers communicate inside Docker Compose?

Answer

Containers communicate through the automatically created Docker network using service names.


Depends On

Controls startup order.

services:
  backend:
    depends_on:
      - postgres
Enter fullscreen mode Exit fullscreen mode

Docker starts:

Postgres
    ↓
Backend
Enter fullscreen mode Exit fullscreen mode

Important:

depends_on does not wait until the database is ready.

It only starts containers in order.

Interview Question:

Does depends_on guarantee database readiness?

Answer

No. It only guarantees startup order.


Restart Policies

Automatically restart containers.

restart: always
Enter fullscreen mode Exit fullscreen mode

Options:

restart: always

restart: unless-stopped

restart: on-failure

restart: no
Enter fullscreen mode Exit fullscreen mode

Common production setting:

restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode

Command

Override Dockerfile CMD.

Dockerfile:

CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Compose:

command: npm run dev
Enter fullscreen mode Exit fullscreen mode

Compose command takes precedence.


Healthcheck

Monitors container health.

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000"]
  interval: 30s
  timeout: 10s
  retries: 3
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Better monitoring
  • Automatic recovery
  • Production readiness

Profiles

Run only selected services.

services:
  postgres:
    profiles:
      - development
Enter fullscreen mode Exit fullscreen mode

Run:

docker compose --profile development up
Enter fullscreen mode Exit fullscreen mode

Useful for:

  • Development
  • Testing
  • Production

Real World Example

Node.js + PostgreSQL

services:
  backend:
    build: .

    ports:
      - "3000:3000"

    environment:
      DATABASE_URL: postgresql://admin:secret@postgres:5432/app

    depends_on:
      - postgres

  postgres:
    image: postgres:16

    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

Start:

docker compose up
Enter fullscreen mode Exit fullscreen mode

Everything starts automatically.


Common Docker Compose Commands

Start:

docker compose up
Enter fullscreen mode Exit fullscreen mode

Background mode:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Stop:

docker compose down
Enter fullscreen mode Exit fullscreen mode

View logs:

docker compose logs
Enter fullscreen mode Exit fullscreen mode

Follow logs:

docker compose logs -f
Enter fullscreen mode Exit fullscreen mode

List containers:

docker compose ps
Enter fullscreen mode Exit fullscreen mode

Restart:

docker compose restart
Enter fullscreen mode Exit fullscreen mode

Build:

docker compose build
Enter fullscreen mode Exit fullscreen mode

Rebuild:

docker compose up --build
Enter fullscreen mode Exit fullscreen mode

Common Interview Questions

What is Docker Compose?

A tool used to define and manage multi-container Docker applications using a YAML file.


Dockerfile vs Docker Compose?

Dockerfile Docker Compose
Builds Images Runs Containers
Defines Environment Defines Services
Creates Images Creates Application Stack

How do containers communicate?

Through Docker networks using service names.


What is depends_on?

Defines container startup order.


Does depends_on wait for readiness?

No.


What is the purpose of volumes?

Persistent data storage.


What is the difference between bind mounts and named volumes?

Bind Mount Named Volume
Uses Host Directory Managed By Docker
Good For Development Good For Production

What happens when docker compose down is executed?

Containers and networks are removed.

Volumes remain unless explicitly deleted.


Can Compose build images?

Yes.

Using:

build: .
Enter fullscreen mode Exit fullscreen mode

Production Best Practices

  1. Use explicit image versions.
image: postgres:16
Enter fullscreen mode Exit fullscreen mode

Avoid:

image: postgres:latest
Enter fullscreen mode Exit fullscreen mode
  1. Use healthchecks.

  2. Use named volumes for databases.

  3. Store secrets in environment files.

  4. Separate development and production configurations.

  5. Use restart policies.

  6. Avoid hardcoded credentials.

  7. Keep services isolated.


Common Mistakes

Mistake Problem
Using latest tag Unexpected updates
No volumes Data loss
No healthchecks Difficult monitoring
Hardcoded secrets Security risk
Using localhost for DB Container communication failure

Docker Compose Revision Sheet

Keyword Purpose
services Define containers
build Build image
image Pull image
container_name Custom name
ports Port mapping
environment Runtime variables
env_file External variables
volumes Persistent storage
networks Service communication
depends_on Startup order
restart Auto restart
command Override CMD
healthcheck Health monitoring
profiles Environment-specific services

Docker Compose Interview Scenarios

In real interviews, Docker Compose questions are usually scenario-based.

Interviewers want to evaluate:

  • Service communication
  • Networking knowledge
  • Volume management
  • Environment variables
  • Startup dependencies
  • Production readiness

This guide contains common interview scenarios and their solutions.


Scenario 1: Backend + PostgreSQL

Interview Question

You have a Node.js backend and PostgreSQL database.

Requirements:

  • Backend should run on port 3000
  • PostgreSQL should run on port 5432
  • Backend should connect to PostgreSQL
  • Database data should persist after container restart

Write a Docker Compose file.


Solution

services:
  backend:
    build: .

    ports:
      - "3000:3000"

    environment:
      DATABASE_URL: postgresql://admin:secret@postgres:5432/app

    depends_on:
      - postgres

  postgres:
    image: postgres:16

    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

Interview Explanation

Backend connects using:

postgres
Enter fullscreen mode Exit fullscreen mode

NOT

localhost
Enter fullscreen mode Exit fullscreen mode

Because containers communicate through service names.

Correct:

DATABASE_URL=postgresql://admin:secret@postgres:5432/app
Enter fullscreen mode Exit fullscreen mode

Wrong:

DATABASE_URL=postgresql://admin:secret@localhost:5432/app
Enter fullscreen mode Exit fullscreen mode

Follow-Up Questions

Why use a volume?

To prevent database data loss.

Why use depends_on?

To ensure PostgreSQL starts before Backend.

Does depends_on wait for database readiness?

No.


Scenario 2: Backend + Redis

Interview Question

Create a Compose file where:

  • Backend runs on port 3000
  • Redis runs on port 6379
  • Backend uses Redis for caching

Solution

services:
  backend:
    build: .

    ports:
      - "3000:3000"

    environment:
      REDIS_URL: redis://redis:6379

    depends_on:
      - redis

  redis:
    image: redis:7
Enter fullscreen mode Exit fullscreen mode

Interview Explanation

Backend can access Redis using:

redis
Enter fullscreen mode Exit fullscreen mode

because Redis service name becomes DNS hostname.


Follow-Up Question

How does Backend discover Redis?

Answer:

Docker Compose automatically creates a network and service names become hostnames.


Scenario 3: Frontend + Backend

Interview Question

You have:

  • React Frontend
  • Express Backend

Both should communicate through Docker network.

Frontend runs on:

localhost:5173
Enter fullscreen mode Exit fullscreen mode

Backend runs on:

localhost:3000
Enter fullscreen mode Exit fullscreen mode

Solution

services:
  frontend:
    build: ./frontend

    ports:
      - "5173:5173"

  backend:
    build: ./backend

    ports:
      - "3000:3000"
Enter fullscreen mode Exit fullscreen mode

Communication

Frontend should call:

http://backend:3000
Enter fullscreen mode Exit fullscreen mode

inside Docker network.

Not:

http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

Interview Trap

Many candidates use:

localhost
Enter fullscreen mode Exit fullscreen mode

This is wrong because each container has its own localhost.


Scenario 4: Full Stack Application

Interview Question

Create a Compose file containing:

  • Next.js
  • Express
  • PostgreSQL
  • Redis

All services should communicate.


Solution

services:
  frontend:
    build: ./frontend

    ports:
      - "3000:3000"

  backend:
    build: ./backend

    ports:
      - "4000:4000"

    environment:
      DATABASE_URL: postgresql://admin:secret@postgres:5432/app

      REDIS_URL: redis://redis:6379

    depends_on:
      - postgres
      - redis

  postgres:
    image: postgres:16

    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

    volumes:
      - postgres-data:/var/lib/postgresql/data

  redis:
    image: redis:7

volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

Architecture

Frontend
    ↓
Backend
   ↓ ↓
Redis PostgreSQL
Enter fullscreen mode Exit fullscreen mode

Follow-Up Questions

How many networks are created?

Answer:

One default network.


How does Backend connect to PostgreSQL?

Answer:

Using hostname:

postgres
Enter fullscreen mode Exit fullscreen mode

How does Backend connect to Redis?

Answer:

Using hostname:

redis
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Custom Network

Interview Question

Create two services that communicate using a custom Docker network.


Solution

services:
  backend:
    build: .

    networks:
      - app-network

  postgres:
    image: postgres:16

    networks:
      - app-network

networks:
  app-network:
Enter fullscreen mode Exit fullscreen mode

Architecture

backend
     ↓
app-network
     ↑
postgres
Enter fullscreen mode Exit fullscreen mode

Interview Explanation

Both services belong to the same network.

Therefore:

backend
Enter fullscreen mode Exit fullscreen mode

can communicate with:

postgres
Enter fullscreen mode Exit fullscreen mode

Scenario 6: Multiple Networks

Interview Question

You have:

  • Frontend
  • Backend
  • Database

Database should NOT be accessible by Frontend.

Design the network architecture.


Solution

services:
  frontend:
    build: ./frontend

    networks:
      - public

  backend:
    build: ./backend

    networks:
      - public
      - private

  postgres:
    image: postgres:16

    networks:
      - private

networks:
  public:
  private:
Enter fullscreen mode Exit fullscreen mode

Architecture

Frontend
    |
 Public
    |
Backend
    |
 Private
    |
Postgres
Enter fullscreen mode Exit fullscreen mode

Why?

Frontend cannot directly access PostgreSQL.

Only Backend can.

This is a common production setup.


Scenario 7: Persistent Database

Interview Question

Your PostgreSQL data disappears after container recreation.

How would you fix it?


Solution

services:
  postgres:
    image: postgres:16

    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

Follow-Up Question

What happens if the container is deleted?

Answer:

Data remains inside the volume.


Scenario 8: Environment Variables

Interview Question

Move all sensitive values out of compose.yml.


Solution

.env

POSTGRES_USER=admin
POSTGRES_PASSWORD=secret
POSTGRES_DB=app
Enter fullscreen mode Exit fullscreen mode

compose.yml

services:
  postgres:
    image: postgres:16

    env_file:
      - .env
Enter fullscreen mode Exit fullscreen mode

Why?

Better security.

Cleaner configuration.


Scenario 9: Health Checks

Interview Question

Ensure Backend starts only when PostgreSQL becomes healthy.


Solution

services:
  postgres:
    image: postgres:16

    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]

      interval: 10s

      timeout: 5s

      retries: 5
Enter fullscreen mode Exit fullscreen mode

Interview Explanation

Health checks allow Docker to monitor service readiness.


Scenario 10: Production Ready Compose

Interview Question

What would you add before deploying to production?


Expected Answer

  • Named volumes
  • Health checks
  • Restart policies
  • Environment files
  • Fixed image versions
  • Separate networks
  • Resource limits
  • Logging configuration

Example:

restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode
healthcheck:
Enter fullscreen mode Exit fullscreen mode
volumes:
Enter fullscreen mode Exit fullscreen mode
env_file:
Enter fullscreen mode Exit fullscreen mode

Most Common Interview Traps

Trap 1

Using localhost between containers.

Wrong:

localhost
Enter fullscreen mode Exit fullscreen mode

Correct:

service-name
Enter fullscreen mode Exit fullscreen mode

Trap 2

No volume for database.

Result:

Container Deleted
      ↓
Data Lost
Enter fullscreen mode Exit fullscreen mode

Trap 3

Using latest image tag.

Wrong:

image: postgres:latest
Enter fullscreen mode Exit fullscreen mode

Correct:

image: postgres:16
Enter fullscreen mode Exit fullscreen mode

Trap 4

Thinking depends_on waits for readiness.

It does not.

It only controls startup order.


Trap 5

Exposing database publicly.

Wrong:

ports:
  - "5432:5432"
Enter fullscreen mode Exit fullscreen mode

Not always necessary.

Expose only when needed.


15-Minute Interview Revision

Question Expected Answer
How do containers communicate? Service Name
What creates networking? Docker Compose
How to persist data? Volumes
Build vs Image? Custom vs Existing Image
What is depends_on? Startup Order
Does depends_on wait? No
How to store secrets? env_file
Why healthchecks? Readiness Monitoring
Why custom networks? Isolation
Why named volumes? Data Persistence

Conclusion

Docker Compose is used to manage multiple containers as a single application. It simplifies networking, storage, environment configuration, startup order, and deployment. Understanding services, build, image, ports, environment variables, volumes, networks, and depends_on is sufficient for handling most real-world projects and Docker-related interviews.

Top comments (0)