Docker Compose for beginners: a practical guide

MJ

Mateusz JanotaCEO & Founder

Docker lets you package one service. Docker Compose lets you describe the whole local environment: application, database, cache, background worker, and any supporting tools. Instead of starting each container by hand, you keep the setup in one compose.yaml file and run it with one command.

This guide explains Docker Compose from the point of view of everyday development. You will create a small stack, learn the core fields, and see the commands you will use most often.

When Docker Compose helps

Compose is useful when your app needs more than one process:

  • a web application and PostgreSQL,

  • an API and Redis,

  • a worker and a queue,

  • local development tools such as Mailpit or MinIO,

  • test environments that need repeatable services.

The main benefit is consistency. New team members do not need to install PostgreSQL, Redis and other tools manually. They run the same stack as everyone else.

A minimal Compose file

Create compose.yaml in your project root:

yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:18
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

Start the stack:

bash
docker compose up

Compose creates a private network automatically. The app container can reach PostgreSQL using the service name db as the hostname.

Run in the background

During development you usually want services to keep running while the terminal is free.

bash
docker compose up -d
docker compose ps
docker compose logs -f app

Stop the stack without deleting data:

bash
docker compose down

Stop it and remove named volumes when you want a clean database:

bash
docker compose down -v

Build context and Dockerfile

The build: . line tells Compose to build an image from the Dockerfile in the current directory.

dockerfile
FROM node:22-alpine
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
CMD ["pnpm", "dev"]

For production images you would usually split build and runtime stages. For a beginner local setup, clarity is more important than maximum optimization.

Environment variables

Inline environment values are fine for tutorials, but real projects should keep local secrets outside the Compose file.

yaml
services:
  app:
    env_file:
      - .env.local

Never commit real production secrets. Use development-only credentials for local containers.

Volumes: why your database survives restarts

A container can be recreated at any time. A named volume stores data outside the container lifecycle.

yaml
volumes:
  postgres-data:

Without the volume, rebuilding or removing the database container would remove the database files too.

Useful commands

These commands cover most daily work:

bash
docker compose up -d              # start services
docker compose ps                 # show status
docker compose logs -f db          # follow logs
docker compose exec db psql -U app # open shell inside a service
docker compose restart app         # restart one service
docker compose down                # stop services
docker compose down -v             # stop and remove volumes

Common mistakes

The most common issue is using localhost from inside a container. Inside the app container, localhost means the app container itself, not your host machine and not the database container. Use the Compose service name, for example db.

Another common issue is changing the Dockerfile but forgetting to rebuild:

bash
docker compose up --build

Compose is not complicated once you remember the model: services run containers, service names become hostnames, volumes keep data, and one file documents how the local stack fits together.

Have a project in mind?

Message us

Let's talk about how we can help bring your ideas to life.

Zanek

Can't keep up with changes in AI world?

Let us do the heavy lifting. Every week we distill the most important AI developments into a focused 5-minute briefing - so you stay ahead without the noise.

Find out more
Weekly AIonline