Docker Compose cheat sheet
Every Compose command worth remembering, with what it actually does to your project. Examples marked with a play button were executed on Ubuntu 26.04 with Compose 5.4.0 - nothing here shows output that was not captured.
- OSUbuntu 26.04 LTS (resolute)
- Docker Engine29.7.2
- Docker Compose5.4.0
- Architectureamd64
- Commands58
- Reviewed22 August 2026
Lifecycle
-
docker compose up -dCreate and start everything in the background, including the project network.
bash Example session docker compose up -d Container cg-first-web-1 Started Container cg-first-cache-1 Started -
docker compose up -d --buildRebuild images before starting. Needed whenever a Dockerfile or its context changed.
-
docker compose up -d --waitBlock until services are healthy, exiting non-zero if they are not. The right thing for CI.
-
docker compose up -d --force-recreateRecreate containers even when nothing changed. Use to pick up an edit Compose thinks is a no-op.
-
docker compose downStop and remove containers and the project network. Named volumes SURVIVE.
bash Example session docker compose down Container cg-first-web-1 Removed Network cg-first_default Removed -
docker compose down -vWhole-hostAlso delete named volumes. No confirmation, no undo - this is how people lose a dev database.
-
docker compose down --rmi localAlso remove images the project built. Leaves pulled images alone.
bash Example session docker compose down --rmi local Image cg-watch-web:latest Removing Image cg-watch-web:latest Removed -
docker compose down --remove-orphansCautionSweep containers the current file no longer describes. The fix for a network that will not go away.
One service at a time
-
docker compose stop NAMEStop one service, leaving the container in place so it can be started again.
bash Example session docker compose stop web Container cg-first-web-1 Stopping Container cg-first-web-1 Stopped -
docker compose start NAMEStart a stopped service again, keeping its filesystem.
-
docker compose restart NAMEStop and start. Does NOT re-read the Compose file - config changes need up, not restart.
bash Example session docker compose restart web Container cg-watch-web-1 Restarting Container cg-watch-web-1 Started -
docker compose up -d NAMEBring one service (and its dependencies) up, leaving the rest untouched.
-
docker compose rm NAMERemove a stopped service's container without touching the rest of the project.
Seeing what is running
-
docker compose psStatus of this project only - unlike docker ps, which shows the whole machine.
bash Example session docker compose psNAME SERVICE STATUS PORTScg-first-cache-1 cache Up Less than a second 6379/tcpcg-first-web-1 web Up Less than a second 0.0.0.0:8099->80/tcp -
docker compose ps -aInclude stopped services. Plain ps hides them, which hides your problem.
bash Example session docker compose ps -a --format "table {{.Service}}\t{{.Status}}"SERVICE STATUScache Up Less than a secondweb Exited (0) Less than a second ago -
docker compose ps --servicesJust the service names, one per line. Good for scripting.
-
docker compose topProcesses running inside each service, without opening a shell.
-
docker compose eventsLive stream of container events for the project. Useful while reproducing a restart loop.
Logs
-
docker compose logsAll services interleaved, each line prefixed with the service that produced it.
bash Example session docker compose logs --tail 2cache-1 | 1:M 20 Aug 2026 07:33:34.428 * Ready to accept connections tcpweb-1 | 172.19.0.1 - - [20/Aug/2026:07:33:34 +0000] "GET / HTTP/1.1" 200 896 -
docker compose logs -f NAMEFollow one service. The first command to run when something misbehaves.
-
docker compose logs --tail 50Only the last N lines. A long-running service can have a great deal of history.
-
docker compose logs --since 10mTime-bounded, which is usually what you want when correlating with an incident.
Getting inside
-
docker compose exec NAME shInteractive shell in a RUNNING service, addressed by service name rather than container name.
-
docker compose exec NAME CMDRun one command and exit.
bash Example session docker compose exec cache redis-cli pingPONG -
docker compose exec -T NAME CMDDisable TTY allocation. Required when piping input or running from a script.
-
docker compose run --rm NAME CMDCautionStart a NEW throwaway container from the service definition. Does not reuse the running one - and does not publish its ports unless you ask.
-
docker compose exec -u root NAME shCautionEnter as root when the image runs as an unprivileged user and you need to install a debug tool.
Configuration and merging
-
docker compose configPrint the fully resolved file. THE debugging command - it shows what Compose understood, not what you meant.
bash Example session docker compose configname: cg-cfg environment: EXTRA: from-envfile GREETING: from-dotenv image: alpine:3.22 -
docker compose config --servicesList service names without starting anything.
-
docker compose config --profilesList every profile the file defines. Answers "why is my service not starting".
-
docker compose config --volumesList declared volumes - the quick check for the undefined-volume error.
-
docker compose -f a.yaml -f b.yaml upMerge files left to right, later files winning. Explicit -f disables automatic override discovery.
bash Example session docker compose -f compose.yaml logs appapp-1 | greeting=from-dotenv extra=from-envfile -
compose.override.yamlMerged automatically when present, no flags needed. Commit the base, ignore the override.
bash Example session docker compose logs appapp-1 | greeting=overridden-locally extra=from-envfile -
Sequences are replaced, not mergedCautionMappings merge key by key; lists such as ports, volumes and command are overwritten wholesale by the override.
Check the merged result with `docker compose config` rather than reasoning about it. `!override` and `!reset` tags give explicit control.
Environment and secrets
-
.env fileSubstitutes ${VARS} INTO the Compose file. Does not automatically reach the container.
-
environment:Sets variables inside the container. This is the one the process sees.
bash Example session docker compose logs appapp-1 | greeting=from-dotenv extra=from-envfile -
env_file:Loads a file of KEY=value pairs into the container. Merges with environment:, which wins on conflict.
-
secrets:Mounts a value as a file under /run/secrets/. Where passwords belong - variables leak into inspect output and logs.
bash Example session docker compose logs appapp-1 | secret=s3cr3t-value -
${VAR:-default}Inline default, so the file works without a .env present.
-
Shell beats .envCautionAn exported variable in your shell overrides the .env value - in that terminal only, which makes it a confusing bug.
Health and ordering
-
depends_on: [db]CautionOrders CREATION only. Does not wait for the service to work - rarely what you want.
-
condition: service_healthyWaits for the dependency's healthcheck to pass before starting the dependent service.
bash Example session docker compose up -d Container cg-stack-db-1 Waiting Container cg-stack-db-1 Healthy Container cg-stack-api-1 Started -
healthcheck: test:The command that defines ready. Ask what a caller would ask - a query, not a process check.
bash Example session docker compose ps --format "table {{.Service}}\t{{.Status}}"SERVICE STATUSdb Up 3 seconds (healthy) -
docker ps --filter health=unhealthyEvery unhealthy container on the host. The cheapest health dashboard there is.
-
start_period: 30sGrace window during which failures do not count against retries. For services that are legitimately slow to boot.
Profiles
-
profiles: ["debug"]Keeps a service out of ordinary up. Where debug tooling and seed jobs belong.
bash Example session docker compose ps --servicesapp -
docker compose --profile NAME up -dActivate a profile for this command.
bash Example session docker compose --profile debug up -d Container cg-cfg-debug-1 Starteddocker compose ps --servicesappdebug -
COMPOSE_PROFILES=debugActivate persistently for the shell, so you cannot forget the flag on down.
-
down without the profileCautionLeaves the profiled container behind and fails to remove the network. The message blames the resource, not the profile.
bash Example session docker compose down Network cg-cfg_default Removing Network cg-cfg_default Resource is still in use
Development loop
-
docker compose watchSync or rebuild on file changes. Foreground, development only.
bash Example session docker compose watchWatch enabledSyncing service "web" after 1 changes were detected -
action: syncCopy the changed file into the running container. No rebuild, no restart.
bash Example session curl -s http://localhost:8099<h1>version two - edited on the host</h1> -
action: rebuildRebuild the image instead. For changes a copy cannot express, such as a dependency manifest.
-
docker compose build --no-cacheCautionRebuild project images ignoring the cache. Slow on purpose.
Traps worth knowing
-
Up is not readyCautionA container reports Started before the process inside it serves anything. curl exits 56 in the gap.
bash Example session curl -s http://localhost:8099# no output, exit 56 - connection reset while the server was still booting -
restart does not re-read the fileCautionChanging compose.yaml then running restart applies nothing. Use up -d, which recreates what changed.
-
The project name is the directory nameTwo checkouts in identically named directories fight over container names. Set name: or -p.
-
POSTGRES_* only apply on first initWhole-hostOnce the volume holds a database those variables are ignored. Changing them means discarding the volume.
-
version: is obsoleteThe top-level version key does nothing and now warns. Delete it.
No command matches that search.