Docker Compose — Top-Level Keys
A compose.yml file has several top-level keys that define different aspects of your application stack. This page explains each one.
The Five Top-Level Keys
# compose.yml — all top-level keys
name: myapp # Optional: project name
services: # REQUIRED: container definitions
web:
image: nginx
db:
image: postgres
volumes: # Optional: named volumes
db-data:
networks: # Optional: custom networks
backend:
configs: # Optional: configuration files
nginx-conf:
file: ./nginx.conf
secrets: # Optional: sensitive data
db-password:
file: ./db-password.txt
services (Required)
The services: key defines your containers. This is the only required top-level key. Every service becomes a running container.
services:
web:
image: nginx:alpine
ports:
- "80:80"
api:
build: ./api
ports:
- "3000:3000"
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
Each key under services: is a service name that you choose. It becomes the hostname for DNS resolution within the Compose network.
volumes (Optional)
The volumes: key defines named volumes for persistent data:
services:
db:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data: # Named volume declaration
Named volumes persist data across docker compose down and docker compose up cycles. Without them, database data would be lost when containers are recreated.
┌──────────────────────────────────┐
│ Named Volume: db-data │
│ ┌────────────────────────┐ │
│ │ /var/lib/postgresql/data│ │
│ │ tables, indexes, WAL │ │
│ └────────────────────────┘ │
│ │
│ Survives: docker compose down │
│ Removed: docker compose down -v│
└──────────────────────────────────┘
networks (Optional)
The networks: key defines custom networks for service isolation:
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
┌─────── frontend ───────┐
│ ┌─────┐ ┌─────┐ │
│ │ web │───│ api │ │
│ └─────┘ └──┬──┘ │
└───────────────┼────────┘
│
┌─────── backend ────────┐
│ ┌──┴──┐ │
│ │ api │ │
│ └──┬──┘ │
│ ┌──┴──┐ │
│ │ db │ │
│ └─────┘ │
└────────────────────────┘
web can talk to api (frontend network)
api can talk to db (backend network)
web CANNOT talk to db (different networks)
If you don’t define any custom networks, Compose creates a default network that all services join automatically.
configs (Optional)
The configs: key mounts configuration files into containers:
services:
web:
image: nginx
configs:
- source: nginx-conf
target: /etc/nginx/nginx.conf
configs:
nginx-conf:
file: ./nginx.conf
Configs are similar to bind mounts but are designed for configuration data and are immutable at runtime.
secrets (Optional)
The secrets: key handles sensitive data:
services:
db:
image: postgres:16
secrets:
- db-password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db-password
secrets:
db-password:
file: ./db-password.txt
Secrets are mounted as files at /run/secrets/<name> inside the container. They’re more secure than environment variables because they don’t appear in docker inspect output.
Summary
| Key | Purpose | Required |
|---|---|---|
name: |
Project name | Optional |
services: |
Container definitions | Yes |
volumes: |
Named persistent volumes | Optional |
networks: |
Custom network isolation | Optional |
configs: |
Configuration files | Optional |
secrets: |
Sensitive data | Optional |
Quick Reference
| Item | Detail |
|---|---|
| services | Container definitions — the only required key |
| volumes | Named volumes for persistent data |
| networks | Custom network isolation between services |
| configs | Configuration files mounted into containers |
| secrets | Sensitive data at /run/secrets/ |
| name | Project name (overrides directory name) |