Docker Compose
How it works
A developer describes the application in a compose.yaml file using top-level elements: services (the computing components of the application), networks (how services communicate with each other), volumes (persistent data shared across services), and optionally configs and secrets. Each service points to an image to pull or a build context, plus ports, environment variables, dependencies (depends_on), healthchecks and mounted volumes. The docker compose up command reads the file, builds or pulls images, creates a shared network, starts the containers in the right order and wires them together using service names as DNS hosts. Companion commands (down, ps, logs, exec, build) cover the rest of the lifecycle. Compose V2 ignores the deprecated version element and interprets the file according to the Compose Specification.
Problem solved
Running a real application usually requires several cooperating containers (API, database, cache, queue, model serving) wired together over a network and persisting data in volumes. Doing this by hand with many docker run commands is tedious, non-reproducible and hard to version. Compose solves this by describing the whole stack as one file in the repository and recreating an identical environment with a single command.
Components
A single YAML file (compose.yaml by default, compose.yml as an alternative) in the working directory, describing services, networks, volumes and optionally configs and secrets. It is the source of truth for the stack and lives in the repository.
Each service is a container (or a set of them) run from a given image or build context, with ports, environment variables, dependencies and healthchecks. It is the main building block of a Compose file.
Services communicate with each other through networks. Compose creates a default network for the project so services address each other by name as DNS hosts; additional isolated networks can also be defined.
Services store and share persistent data in volumes that live independently of the container lifecycle. Typically used for databases, vector indexes or model caches.
A CLI plugin (Compose V2, written in Go) invoked as docker compose. Commands up/down/ps/logs/exec/build cover start, stop, status, logs and one-off commands. The older v1 was a separate Python tool invoked as docker-compose.
Implementation
Older materials use the docker-compose command (v1, Python), whereas current Compose V2 is a CLI plugin invoked as docker compose. Differences include V2 ignoring the version element.
By default depends_on only enforces container start order; it does not wait until a service (e.g. a database) is actually ready to accept connections.
Compose typically manages a stack on a single host and does not provide multi-node scheduling, self-healing or cross-machine autoscaling โ those are jobs for Kubernetes or Swarm.
Publishing the same host ports from several stacks causes conflicts, and host bind-mounts are a common source of permission and performance issues (especially on macOS/Windows).
Evolution
First public beta of the tool (0.0.1) per Wikipedia; the project originates from the earlier Fig tool (the predecessor of Compose).
Compose v1 released in 2014, written in Python and invoked as docker-compose; the production-ready 1.0 became available on 16 October 2014.
Introduction of the 2.x Compose file format.
Introduction of the 3.x Compose file format.
Compose V2 announced in 2020: rewritten in Go, invoked as docker compose (CLI plugin). It ignores the version element and relies entirely on the open Compose Specification to interpret the file.
Compose v5 released in 2025, functionally identical to Compose V2 but introducing an official Go SDK for programmatic integration.
Hyperparameters (configurable axes)
The set of container services making up the application; the primary configuration axis of a Compose file.
For each service: a prebuilt image to pull, or a local build context (Dockerfile).
Publishing container ports on the host; a common source of conflicts when running multiple stacks.
Configuring services via environment variables and .env files (e.g. API keys, model endpoints).
Service start order and readiness conditions; depends_on by itself only waits for start, not full readiness.
Conditionally enabling subsets of services (e.g. dev vs. full stack) within a single Compose file.