Skip to content
Commitpedia
Log in Join & edit

Docker Compose: run a small web app with a database

Docker Compose describes several containers, their ports, volumes and environment in one compose.yaml file, then starts them all with docker compose up.

Edit history of Docker Compose: run a small web app with a database: 1 recorded edit
Edit history · 1 edit
Type
Article
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Reading
3 min

Most apps are more than one process: a web server, a database, maybe a cache. Starting each with a long docker run command gets old fast. Docker Compose lets you describe them in one YAML file and manage them together. Compose v2 is a Docker CLI plugin, so the command is docker compose with a space. The older docker-compose tool with a hyphen is no longer maintained.

The project layout

myapp/
  compose.yaml
  .env
  web/
    Dockerfile
    requirements.txt
    app.py

The web folder holds a small Python app with its own Dockerfile, such as the one shown in the Docker basics article. The app reads its database address from an environment variable.

compose.yaml

services:
  web:
    build: ./web
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql://app:${POSTGRES_PASSWORD}@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_DB: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  pgdata:

A few things worth noticing:

  • Service names are hostnames. Compose puts all services on a shared network, so the web app reaches the database at db:5432, not localhost.
  • Only web publishes a port. The database is reachable by other services but not from outside, which is safer. Add ports: ["5432:5432"] to db only if you need to connect from your machine.
  • The named volume pgdata keeps database files when containers are recreated.
  • depends_on with service_healthy waits until the healthcheck passes, not just until the container starts. Without it, the app may try to connect before Postgres accepts connections.
  • The top-level version: key from old tutorials is obsolete and can be left out.

Keep secrets in .env

Compose automatically reads a file named .env next to compose.yaml and substitutes ${VARIABLES}. Add .env to .gitignore and commit a .env.example with placeholder values instead.

POSTGRES_PASSWORD=change-me-locally

Everyday commands

docker compose up -d            # build if needed, start everything in the background
docker compose ps               # status of this project's services
docker compose logs -f web      # follow one service's logs
docker compose exec db psql -U app app   # open a SQL shell in the db
docker compose up -d --build    # rebuild after changing the Dockerfile or dependencies
docker compose restart web      # restart one service
docker compose down             # stop and remove containers and the network
docker compose down -v          # ...and delete volumes: this erases the database

Run these from the folder that contains compose.yaml. Compose names the project after the folder, so two checkouts in different folders do not collide.

Live code reloading in development

Rebuilding the image after every edit is slow. During development, mount your source folder into the container so changes appear immediately:

services:
  web:
    build: ./web
    volumes:
      - ./web:/app
    command: ["python", "app.py"]

Keep this in a separate compose.override.yaml, which Compose merges automatically when present, so your base file stays production-like.

Troubleshooting

  • Bind for 0.0.0.0:8000 failed: port is already allocated: something else uses port 8000. Stop it or change the left side of the mapping, for example "8001:8000".
  • The app cannot reach the database: check that it uses the service name db as host, and look at docker compose logs db.
  • Changes to the Dockerfile do nothing: up reuses existing images, so add --build.
  • Validate the file with docker compose config, which prints the fully merged configuration or an error.

See also

  • 0055 Docker basics: images, containers and the commands you need An image is a read-only package of an app and its dependencies, and a container is a running instance of it. Learn… Beginner · Concept · Linux, macOS, Windows Article Docker basics 15 Oct 2026
  • 0250 Containerize a Node.js app and run it with PostgreSQL using Docker Compose Package a small Node.js web app in a multi-stage Docker image, then run it next to PostgreSQL with Docker Compose, named volumes,… Intermediate · Tutorial · Linux, macOS, Windows Article Docker basics · Docker Compose · PostgreSQL 15 Oct 2026

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. commitpedia-admin +3,950 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?