Docker Compose
Compose v2 (`docker compose`) runs a multi-container app from one model. Know how it names and connects resources, how it orders startup, how environment values are resolved, and how multiple files merge.
Key points
- 1
Every project gets a
<project>_defaultnetwork. Services reach each other by service name on the container port; publishedportsare only for clients outside the network, andexposenever publishes. - 2
The project name (from
-p, thenCOMPOSE_PROJECT_NAME, then top-levelname:, then the folder name) prefixes containers, networks and named volumes. Renaming the folder means new, empty volumes. - 3
depends_onshort syntax only orders startup. Add ahealthcheckandcondition: service_healthyto wait for readiness, orservice_completed_successfullyfor one-shot jobs such as migrations. - 4
The
.envfile feeds interpolation of the Compose file; it is not injected into containers. Interpolation precedence: shell, then--env-file, then.env. Container precedence:run --env, thenenvironment, thenenv_file, then imageENV. - 5
Without
-f, Compose mergescompose.override.yamlontocompose.yaml. With-f, only the listed files are merged, in order: mappings merge, sequences append,commandandentrypointare replaced, and ports and volumes merge by their unique key. Use!resetto clear inherited values. - 6
docker compose rundoesn't publish ports unless you pass--service-ports.downkeeps named volumes unless you add-v, and never removes external resources or bind-mounted host folders. - 7
Compose Watch keeps dev containers in step with source:
syncfor hot-reloaded files,rebuildfor dependency manifests,sync+restartfor config read at startup. It only tracks services with abuildsection.
Common traps
${VAR-default}and${VAR?err}treat an empty value as set; only the colon forms${VAR:-default}and${VAR:?err}catch blank values likeDB_PASSWORD=.With both
imageandbuildand nopull_policy, Compose pulls the image first and only builds if it's missing, so a registry tag can silently replace your local code.Write
$$in the Compose file when a$VARmust be expanded by the container's shell (for example in a healthcheck), otherwise Compose substitutes it at load time.
Read the source
Test yourself on Docker Compose
Ten questions, with the answer and explanation after each one.