Introduction to Docker Compose

Introduction to Docker Compose

Bitnesia Sep 12, 2026 9 ID

Running a single container via docker run is sufficient for simple applications, but real-world applications rarely stand alone. A typical web application usually requires a database, a cache, and perhaps a reverse proxy running concurrently, interconnected through the same network, with a startup order that must be considered. Running all of these manually through a long series of docker run commands, and repeating that process every time the environment needs to be recreated, quickly becomes cumbersome for both Developers managing local environments and Sysadmins/DevOps Engineers setting up staging environments. This chapter covers Docker Compose as the solution: what Docker Compose is, how to install it, the basic syntax of compose.yaml, and how file versioning and compatibility work in Compose V2, which is the current standard.

16.1 What is Docker Compose?

Docker Compose is a tool for defining and running multi-container Docker applications simultaneously using a single configuration file in YAML format. Instead of running each container one by one using docker run with lengthy options, all the services, networks, and volumes required by the application can be written once in the compose.yaml file and executed together using a single command.

16.1.1 Problems Solved by Docker Compose

Consider a simple example: a web application needs a web service and a redis database running simultaneously and connected to each other. Without Compose, a Developer would have to run two separate docker run commands, ensure both are on the same network, manually manage startup ordering, and repeat the entire process every time the environment is rebuilt from scratch. As more services become involved, the list of commands that must be remembered and executed consistently grows exponentially longer.

Docker Compose addresses these challenges by offering key benefits, as outlined in the official Docker documentation:

  • Defines the entire multi-container application in a single YAML file.
  • Guarantees consistent environments across development, testing, and production, as the same service definition is utilized at all stages.
  • Automatically handles container startup ordering and inter-container networking (linking).
  • Streamlines the development workflow and reduces the time needed to set up new environments.
  • Ensures each service runs in its own isolated container to prevent conflicts between services.

In practice, the most significant impact is observed in environment consistency. A Developer who clones a repository and runs docker compose up immediately gets a workspace identical to their teammates without needing to manually install databases or other dependencies directly on their local machine.

16.1.2 Compose V1 vs Compose V2

Docker Compose has two generations of implementation that must be distinguished. Compose V1 was first released in 2014, written in Python, and executed using the docker-compose command (with a hyphen). Compose V2, announced in 2020, was rewritten in Go and runs as an official Docker CLI plugin using the docker compose command (two separate words, without a hyphen).

Compose V1 is deprecated and no longer actively maintained. This series consistently uses the docker compose syntax (Compose V2) as the standard, except when explicitly discussing legacy contexts. Docker released Compose v5 in 2025, which is functionally identical to Compose V2, with the primary difference being the addition of an official Go SDK for programmatic integration; the major version number jumped to v5 to avoid confusion with older Compose file format versions that also used "v2" and "v3" labels. Both docker compose v2 and v5 share the same command syntax, so the concepts in this chapter apply to both.

16.2 Installing Docker Compose

The most practical way to obtain Docker Compose is through Docker Desktop, as Docker Desktop bundles Docker Compose along with the prerequisite Docker Engine and Docker CLI. For Linux systems without Docker Desktop, Docker Compose is installed as a separate CLI plugin named docker-compose-plugin.

16.2.1 Installation via Docker Desktop (macOS and Windows)

On macOS and Windows (via WSL2), installing Docker Desktop automatically includes the Docker Compose plugin, so no separate installation steps are required. Once Docker Desktop is installed, the active Compose version can be verified via the About Docker Desktop menu in the Docker menu, or through the terminal using the command docker compose version, exactly like the verification step on Linux.

16.2.2 Plugin Installation on Linux

For Debian/Ubuntu-based distributions, install docker-compose-plugin via apt after configuring the official Docker repository.

sudo apt-get update
sudo apt-get install docker-compose-plugin

For RPM-based distributions such as CentOS, Fedora, or RHEL, use yum or dnf according to the package manager used by the distribution.

sudo yum update
sudo yum install docker-compose-plugin

If the official Docker repository is not yet registered in the package manager, follow the repository setup instructions for your distribution before executing the installation commands above. Sysadmins and DevOps Engineers managing Linux-based production servers typically install Docker Engine and the Compose plugin via this package manager approach, rather than using Docker Desktop, which is tailored for desktop environments.

16.2.3 Manual Plugin Installation (Alternative)

If your distribution package manager does not provide docker-compose-plugin, the plugin can be installed manually by downloading the binary release directly into the Docker CLI CLI plugins directory.

DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/<version>/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose

Replace the <version> placeholder with the desired Compose release tag, such as v2.39.4, based on the official releases listed on the docker/compose GitHub page. The chmod +x command above is required to grant execution permissions to the downloaded binary.

16.2.4 Verifying Installation

After completing the installation, verify that Docker Compose is properly installed and accessible via the Docker CLI using the docker compose version command.

docker compose version
Docker Compose version v2.39.4

If the command outputs an error message such as docker: 'compose' is not a docker command, the plugin is either not installed correctly or is not detected by the Docker CLI. Recheck if the binary file docker-compose exists in the ~/.docker/cli-plugins/ directory (for manual installations), or rerun the plugin installation commands appropriate for your Linux distribution.

16.3 compose.yaml Syntax

Docker Compose configuration files are commonly named compose.yaml (the legacy docker-compose.yml filename from Compose V1 is also supported for backward compatibility). This file is structured in YAML format and contains top-level elements that define the overall application setup.

16.3.1 Top-Level Elements: services, networks, volumes

The three most frequently used top-level elements in a compose.yaml file are services, networks, and volumes. The services element defines each container that makes up the application, networks defines custom networks to connect those services, and volumes defines persistent storage shared across services.

services:
  web:
    build: .
    ports:
      - "8000:5000"
    environment:
      - REDIS_HOST=redis

  redis:
    image: redis:alpine

The example above defines two services: web, which is built from the local Dockerfile in the current directory using the build instruction, and redis, which uses the public redis:alpine image from Docker Hub via the image instruction. The ports option maps port 8000 on the host machine to port 5000 inside the web container, while environment configures environment variables used by the application to locate the Redis server. Both services are automatically connected to the same default network when executed through Compose, allowing the web service to reach redis using its service name as the hostname without additional manual network configuration.

16.3.2 Running and Stopping the Application

Once compose.yaml is configured, launch the application by running docker compose up in the directory containing the file.

docker compose up -d

The -d flag runs all services in detached mode in the background, similar to the -d flag in docker run. Docker Compose automatically creates a dedicated network for the application, pulls or builds necessary images, and launches all defined services. Check the status of running services using docker compose ps.

docker compose ps

To stop and clean up all resources created by Compose (containers, default networks, but excluding named volumes unless specified), run docker compose down.

docker compose down

Note that executing docker compose down without extra flags preserves named volumes, keeping stored data safe. If you also need to remove named volumes, include the -v flag. Use caution with this flag, as it permanently deletes all data stored inside those volumes.

16.3.3 YAML Formatting Guidelines

Because compose.yaml is written in YAML, indentation formatting using spaces (not tabs) strictly controls configuration hierarchy. Each level beneath a key must consistently use the exact same number of spaces, as YAML relies on indentation rather than brackets like JSON. An indentation discrepancy as small as a single space can cause Compose to misinterpret the file structure or fail during parsing.

Developers transitioning from JSON to YAML often run into formatting issues, particularly when copying configurations from external sources containing tabs instead of spaces. Modern code editors typically provide YAML validation plugins that can catch indentation issues before running docker compose up.

16.4 Versioning and Compatibility

The Compose file format has evolved across multiple iterations since Compose V1 was introduced. Understanding its history helps prevent confusion when encountering legacy compose.yaml files that still contain a top-level version attribute.

16.4.1 Evolution from Versioned Formats to the Compose Specification

Compose V1 used three main schema generations marked by top-level version attributes: format version 1 (released with Compose 1.0.0 in 2014, lacking a top-level services block and incompatible with Compose V2 and v5), format version 2.x (released with Compose 1.6.0 in 2016), and format version 3.x (released with Compose 1.10.0 in 2017 with dedicated options for Docker Swarm). Format 2.x and 3.x shared many similarities, which often led to confusion regarding feature availability across versions.

To address this complexity, formats 2.x and 3.x were consolidated into a single standard called the Compose Specification (compose-spec.io). Compose V2 and v5 rely on the Compose Specification as their core standard. Unlike previous versioned formats, the Compose Specification follows a rolling release model (updated incrementally without major schema numbers) and makes top-level version declarations optional.

16.4.2 Current Status of the version Element

The top-level version element in compose.yaml is now considered obsolete under the Compose Specification. It is retained purely for backward compatibility and functions only as informational metadata. If included, Compose V2 and v5 will display a warning indicating that the field is obsolete.

services:
  web:
    image: nginx:alpine

The compose.yaml example above intentionally omits the version key entirely, as it is no longer required. Docker Compose V2 and v5 validate configurations against the latest Compose Specification schema regardless of whether a version tag is present. If an unrecognized field is encountered (such as a feature from a newer spec version than the installed Compose tool supports), Compose displays a warning rather than failing completely.

16.4.3 Compatibility with docker stack deploy

One notable exception regarding compatibility involves the docker stack deploy command used for Docker Swarm deployments. This command relies on the legacy Compose file format version 3 from Compose V1 and is incompatible with the latest Compose Specification. Features introduced in the Compose Specification, such as modern rolling update rules, advanced healthcheck parameters, rollback_config, and specific stop_grace_period settings, may not behave identically when deployed using docker stack deploy.

Sysadmins and DevOps Engineers authoring compose.yaml files for use across both docker compose up in local development and docker stack deploy in Swarm production should account for these operational differences. Configuration files that function as expected using docker compose are not guaranteed to work identically under docker stack deploy. When targeting Swarm, validate configurations directly using docker stack deploy within a staging environment rather than relying solely on local docker compose up tests.

16.4.4 Feature Comparison Summary

AspectCompose V1Compose V2 / v5
CLI Commanddocker-composedocker compose
Implementation LanguagePythonGo
File FormatVersion 1, 2.x, 3.x (numbered)Compose Specification (rolling)
version ElementRequired to define parsing behaviorOptional, obsolete if specified
Support StatusDeprecatedActively Developed

As a best practice going forward, use the docker compose command syntax and author compose.yaml files without a top-level version field, unless maintaining legacy files or explicitly targeting docker stack deploy pipelines.