The Everyday Commands
You will use about eight Compose commands. Everything else is for special occasions. (Lifecycle commands need the Docker daemon running — the file-validation ones don't.)
The core loop
docker compose up -d # create + start everything, detached
docker compose ps # what's running in this project
docker compose logs -f # follow all services' logs (Ctrl+C detaches)
docker compose down # stop + remove containers and networks
That's 90% of Compose. A few notes:
upwithout-dattaches to the logs in your terminal — great for watching a first start, Ctrl+C stops everything.psshows only this project's containers (it knows by the project name), unlikedocker pswhich shows the whole machine.logs -fprefixes each line with the service name. Add a service name (docker compose logs -f db) to follow just one.-n 100shows the last 100 lines;--since 10mshows the last ten minutes.downkeeps your named volumes. Your database survives adown. Onlydown -vdeletes volumes — and you should type that-vdeliberately, every time (Updating and Recreating).
Reaching into containers
docker compose exec web sh # open a shell in the running "web" container
docker compose exec db psql -U postgres # run one command in "db"
docker compose run --rm web sh # like exec, but starts a NEW one-off container
exec = into the running one. run = a fresh throwaway
(--rm cleans it up after). Use run for one-shot tasks
against the project's network and volumes.
Images: pull, build, config
docker compose pull # download the newest of every image: tag
docker compose build # (re)build every service with a build: section
docker compose up -d --build # rebuild, then start — the common combo
docker compose config # render + validate the file, no daemon needed
config is the odd one out: it's pure file processing,
which is why every sample in this guide was validated
with it. Run it after every edit — it catches typos
before they become runtime mysteries.
Modern Compose also has --dry-run on up/down
(docker compose up --dry-run -d): it prints what would
happen without doing it. Needs the daemon, but it's the
safest way to preview a scary command.
Multiple files: -f and the override pattern
docker compose -f compose.yaml -f compose.prod.yaml up -d
Later files override earlier ones — same service, same key, last file wins. The beloved pattern:
compose.yaml— the base, works everywhere.compose.override.yaml— auto-loaded when present; dev-only bits (bind-mounted source code, published debug ports).compose.prod.yaml— applied explicitly with-f; production tweaks (tighter restarts, no debug ports).
Keep secrets and environment-specific settings in the override files, not the base.
Targeting services
Almost every command takes service names at the end:
docker compose up -d db # start only db (and its dependencies)
docker compose logs -f web
docker compose restart web # restart one service
docker compose stop web # stop one service (keeps it: start brings it back)
stop vs down: stop halts the containers but keeps
them (and the project) around; down tears the project
down to volumes and images.
Command cheat sheet
| I want to... | I run... |
|---|---|
| Start everything | docker compose up -d |
| Watch it start | docker compose up (no -d) |
| See what's running | docker compose ps |
| Read the logs | docker compose logs -f [service] |
| Shell into a container | docker compose exec <service> sh |
| Stop everything, keep data | docker compose down |
| Nuke everything incl. data | docker compose down -v |
| Update images | docker compose pull && docker compose up -d |
| Check my YAML | docker compose config --quiet |