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.
Not checked by a trusted editor yet Last edited Outdated?
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, notlocalhost. - Only
webpublishes a port. The database is reachable by other services but not from outside, which is safer. Addports: ["5432:5432"]todbonly if you need to connect from your machine. - The named volume
pgdatakeeps database files when containers are recreated. depends_onwithservice_healthywaits 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
dbas host, and look atdocker compose logs db. - Changes to the Dockerfile do nothing:
upreuses existing images, so add--build. - Validate the file with
docker compose config, which prints the fully merged configuration or an error.
Did this work for you?
No votes yet. Be the first.
If it did not work, the report form below tells the editors what went wrong.
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 · Explains an idea · 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 · Guided project · Linux, macOS, Windows Article Docker basics · Docker Compose · PostgreSQL 15 Oct 2026
- 0268 What is a container? A container is a lightweight box that packs a program with everything it needs so it runs the same on any computer. Beginner · Explains an idea · Any system Article Docker basics 15 Oct 2026
- 0327 Docker images, containers and volumes explained An image is a read-only template, a container is a running copy of it with a thin writable layer, and a volume… Beginner · Explains an idea · Linux, macOS, Windows Article Docker basics 15 Oct 2026
- 0328 Install Docker Engine on Ubuntu and Debian Set up Docker's official apt repository, install Docker Engine with the Compose and Buildx plugins, run hello-world and let your user run… Beginner · Step by step · Linux Article Docker basics · Packages & updates 15 Oct 2026
- 0329 Docker CLI cheat sheet The Docker commands you reach for every day, grouped by what they act on: containers, images, volumes, networks, logs and cleanup, with… Beginner · Cheat sheet · Linux, macOS, Windows Article Docker basics 15 Oct 2026
Repos in the wild
- docker/compose docker/compose The source of Docker Compose, the tool that defines and runs multi-container applications from a compose.yaml file. Useful for release notes, the issue tracker and the examples directory. GitHub
- Watchtower (maintained fork): automatic container image updates nicholas-fedor/watchtower Watchtower watches your running containers, pulls newer versions of their images and restarts them with the same settings. This fork continues the project after the original containrrr repository was archived. GitHub
- Uptime Kuma: self-hosted uptime monitoring louislam/uptime-kuma Uptime Kuma is a self-hosted monitoring tool with a web UI that checks websites, TCP ports, DNS, Docker containers and more, draws uptime history and sends alerts. One container is all it needs. GitHub
- Traefik: a reverse proxy that configures itself from Docker and Kubernetes traefik/traefik Traefik is an open-source edge router that discovers services from Docker labels, Kubernetes resources and other providers and routes traffic to them, with automatic Let's Encrypt certificates and a dashboard. GitHub
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- Commitpedia +3,950 chars