Appearance
Docker Compose commands cheat sheet
A reference for the docker compose commands you use on a server, grouped by task. Each table lists the command and what it does, followed by the details that cause trouble in practice. Everything here is for Compose v2 and later (the docker compose plugin). If you still type docker-compose, see Docker Compose on Ubuntu for the switch. If Docker is not installed yet, start with install Docker on Ubuntu.
How Compose finds your project
Most commands work on "the current project" without naming it. Compose works it out like this:
- The file. Without
-f, Compose looks forcompose.yaml(orcompose.yml,docker-compose.yaml,docker-compose.yml) in the current folder, then in parent folders. Ifcompose.override.yamlsits next to it, that file is merged on top automatically. - The project name. Taken from
-p, then theCOMPOSE_PROJECT_NAMEvariable, then a top levelname:in the file, and finally the folder name. It prefixes all containers, networks and volumes, so/opt/blog/compose.yamlcreatesblog-web-1,blog_defaultand so on. - Variables. Values for
${VAR}in the file come from your shell and from.envin the project folder.
Practical rule: cd into the project folder before you run anything. Most "my containers are gone" moments are commands run from the wrong folder, which Compose treats as a different, empty project.
Start and stop
| Command | What it does |
|---|---|
docker compose up -d | Create and start all services in the background |
docker compose up -d app | Start only app (and what it depends on) |
docker compose up -d --wait | Start, then wait until services are running or healthy |
docker compose stop | Stop containers, keep them |
docker compose start | Start containers that were stopped |
docker compose restart app | Stop and start app with its existing configuration |
docker compose down | Stop and remove containers and the project network |
docker compose pause / unpause | Freeze and resume processes without stopping them |
docker compose kill | Stop immediately with SIGKILL, no graceful shutdown |
Gotchas:
restartdoes not apply changes. After editingcompose.yamlor.env, rundocker compose up -d. It recreates only the containers whose configuration or image changed and leaves the rest running.upwithout-dattaches your terminal to the logs, and Ctrl+C stops the whole project. On a server you almost always want-d.stopvsdown.stopkeeps the containers and is quick to undo withstart.downremoves them. Data in named volumes survives both.- Slow shutdown. Containers get 10 seconds to exit before they are killed. Databases sometimes need more:
docker compose stop -t 60orstop_grace_period:in the file.
Status and logs
| Command | What it does |
|---|---|
docker compose ps | Running containers of this project, with status and ports |
docker compose ps -a | Include stopped and exited containers |
docker compose ls | All running Compose projects on the server |
docker compose ls -a | All projects, including stopped ones |
docker compose logs -f | Follow the logs of all services |
docker compose logs -f --tail 100 app | Last 100 lines of app, then follow |
docker compose logs --since 30m | Only the last 30 minutes |
docker compose logs -t | Add timestamps to each line |
docker compose top | Processes running inside each container |
docker compose stats | Live CPU and memory usage per container |
docker compose port app 8080 | Which host address a container port is published on |
Gotchas:
logswithout--tailprints everything since the container was created. On a container that has run for months this floods the terminal. Make--tail 100a habit.docker compose lsis the fastest way to find where a project lives: theCONFIG FILEScolumn shows the path of itscompose.yaml.
Run commands inside containers
| Command | What it does |
|---|---|
docker compose exec app sh | Shell in the running app container |
docker compose exec -u root app sh | Same, as root |
docker compose exec db psql -U postgres | Run a tool inside a service |
docker compose exec -T db pg_dump -U postgres mydb > dump.sql | Pipe output to a file on the host |
docker compose run --rm app sh | Start a new one off container from the app service |
docker compose run --rm --no-deps app ./migrate | One off task without starting dependencies |
docker compose cp app:/app/config.yml ./config.yml | Copy a file from a container to the host |
docker compose cp ./config.yml app:/app/config.yml | Copy a file from the host into a container |
Gotchas:
execvsrun.execenters a container that is already running.runcreates a fresh container from the service definition, which is useful for migrations and maintenance scripts, or when the service is stopped.- Always add
--rmtorun. Without it, every run leaves a stopped container behind. rundoes not publish ports from the service definition. Add--service-portsif you need them.- Use
-Twhen piping in or out (> dump.sql,< dump.sql), and in cron jobs. Without it, the allocated TTY can add carriage returns to the output or fail when there is no terminal. bashmay not exist. Many images are based on Alpine or are minimal. Tryshifbashis not found.
Images and builds
| Command | What it does |
|---|---|
docker compose pull | Download newer versions of all images |
docker compose pull app | Only for one service |
docker compose images | Images used by the project's containers |
docker compose build | Build services that have a build: section |
docker compose build --no-cache | Build from scratch, ignoring the layer cache |
docker compose build --pull | Fetch a newer base image before building |
docker compose up -d --build | Rebuild, then start |
docker compose up -d --force-recreate | Recreate containers even if nothing changed |
docker compose up -d --no-deps app | Recreate app without touching its dependencies |
docker compose up -d --pull always | Pull images on every up |
The standard update routine for a project built from published images:
bash
docker compose pull
docker compose up -d
docker image prune -fGotchas:
pullalone changes nothing for running containers. They keep the old image untilup -drecreates them.updoes not rebuild an image that already exists. After changing a Dockerfile or source code, useup -d --build.--force-recreatehelps when a container needs a clean start, for example after changing log settings indaemon.json. It does not pull or rebuild anything.
Check the configuration
| Command | What it does |
|---|---|
docker compose config | Print the final configuration with variables filled in and files merged |
docker compose config --quiet | Only validate, print nothing on success |
docker compose config --services | List service names |
docker compose config --volumes | List named volumes |
docker compose config --images | List images the project uses |
docker compose config --environment | Show the variables used for substitution |
docker compose --dry-run up -d | Show what up would do without doing it |
Gotchas:
configprints secrets. Passwords from.envappear in plain text in its output. Do not paste it into chats or tickets unedited.- Run
config --quietbefore everyupafter editing YAML. Indentation errors show up with a line number instead of a half started project.
Several files and projects
| Command | What it does |
|---|---|
docker compose -f compose.yaml -f compose.prod.yaml up -d | Merge files, later ones override earlier ones |
docker compose -f /opt/blog/compose.yaml ps | Work on a project from any folder |
docker compose -p staging up -d | Run a second copy of the project under another name |
docker compose --env-file .env.prod up -d | Use another variables file |
docker compose --project-directory /opt/blog ps | Set the base folder for relative paths |
Gotchas:
- Repeat the same
-fand-pflags on every command. If you started with-p staging, a plaindocker compose downtargets a different project and does not stop staging. - Setting them once.
COMPOSE_FILE,COMPOSE_PROJECT_NAMEandCOMPOSE_PROFILEScan go into the project's.envfile, so the short commands keep working. Separate several files inCOMPOSE_FILEwith:on Linux. - Relative paths in all files are resolved from the folder of the first file, not of the file they appear in.
Profiles
Profiles mark optional services that do not start by default, for example an admin tool or a one off backup job:
yaml
services:
db:
image: postgres:18
adminer:
image: adminer
profiles: [tools]
ports:
- "127.0.0.1:8081:8080"| Command | What it does |
|---|---|
docker compose up -d | Starts only services without a profile (db) |
docker compose --profile tools up -d | Also starts services in the tools profile |
COMPOSE_PROFILES=tools docker compose up -d | Same, with an environment variable |
docker compose --profile "*" up -d | Enable every profile |
docker compose up -d adminer | Naming a service starts it even if its profile is off |
docker compose --profile tools down | Remove profiled services together with the rest |
Gotcha: a plain docker compose down ignores services in inactive profiles. Their containers keep running. Pass the same --profile to down that you used for up.
Watch mode (development)
watch rebuilds or updates containers automatically when files on disk change. It works only for services with a build: section and a develop.watch block:
yaml
services:
web:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: package.json| Command | What it does |
|---|---|
docker compose watch | Start watching, show sync and rebuild events |
docker compose up --watch | Start the project with watching and normal logs |
The actions are sync (copy changed files into the container), rebuild (build a new image and replace the container) and sync+restart (copy, then restart). Watch mode is meant for development. On a production server, deploy deliberately with pull or build and up -d.
Clean up, and the dangerous flags
| Command | What it does | Data loss? |
|---|---|---|
docker compose down | Remove containers and project networks | No, volumes stay |
docker compose down --remove-orphans | Also remove containers of services deleted from the file | No |
docker compose up -d --remove-orphans | Same cleanup while starting | No |
docker compose rm | Remove stopped service containers | No |
docker compose down --rmi all | Also remove the project's images | No, but they must be pulled again |
docker compose down -v | Also remove named and anonymous volumes | Yes |
docker compose up -d -V | Recreate anonymous volumes instead of reusing them | Yes, for anonymous volumes |
docker compose down -v deletes your data
-v removes the named volumes declared in the file. For a database that means the whole database, with no undo. It is useful when you deliberately want to start over in development. On a server, use plain down, and have a backup before you ever type -v.
Gotchas:
- Orphans. When you rename or delete a service in the file, its old container keeps running and Compose warns about
orphan containers.--remove-orphansremoves them. - External volumes and networks (marked
external: true) are never removed bydown, not even with-v. - Server wide cleanup is done with plain Docker commands, not Compose:
docker image prunefor unused images,docker system dfto see what takes space. Be careful withdocker volume prune --all: it deletes every volume no container uses at that moment, including the data of projects that are currently down. Without--all, current Docker versions only remove unused anonymous volumes.
Coming from docker-compose v1
| Old command | New command |
|---|---|
docker-compose up -d | docker compose up -d |
docker-compose logs -f web | docker compose logs -f web |
docker-compose exec web sh | docker compose exec web sh |
docker-compose -f prod.yml up -d | docker compose -f prod.yml up -d |
Subcommands and most flags kept their names. The visible differences are container names with hyphens (project-web-1 instead of project_web_1) and the version: line at the top of files, which is now ignored.
Related guides
- Docker Compose on Ubuntu: install Compose v2 and build an app plus PostgreSQL project step by step.
- Install Docker on Ubuntu: Docker Engine setup and troubleshooting.
- Back up your VPS: protect volumes before updates and cleanups.