Skip to content

Moving to docker compose v2: a fix that was three years late

Adityo Guni Waluyo

My dev script still called docker-compose in eleven places. Compose v1 has been EOL since June 2023; only a symlink kept it alive.

TL;DR

The dev script still called docker-compose, deprecated since mid-2023, and only survived thanks to a Docker Desktop compatibility symlink masking the problem. Compose v2 turned the command into a docker CLI subcommand, so it's now two words. Swapping the hyphen for a space across all call sites is a tiny commit that prevents CI breakage.

The terminal was open, still sitting in the company website folder. ./dev.sh worked fine: container up, page served. Then I idly opened the script. In cmd_up and ten other functions, the command being called was still docker-compose, hyphen and all, 2016 style.

My first guess: leave it alone. The script has kept working this long, surely its docker-compose hasn't died. That guess was wrong. Compose v1 has been unsupported since June 2023 [1]. And what kept the script running on my laptop wasn't real v1 but a compatibility symlink pointing to v2. The script wasn't healthy; it was quietly leaning on a bridge someone else built.

That symlink is deliberate. Docker Desktop ships an option that makes Compose V2 the default, and Docker's own blog describes the effect: activating it creates a symlink so old scripts that still call docker-compose keep working on the new version [2]. Comfortable. But the side effect is clear: scripts like dev.sh can sleep for years without ever being corrected, while their foundation was replaced long ago.

The fix itself looks exactly like this, two functions from dev.sh:

# before
cmd_up() {
  docker-compose up --build
}

# after
cmd_up() {
  docker compose up --build
}

The same pattern repeats through cmd_start, cmd_logs, cmd_shell (which used to check containers with docker-compose ps --status running), down to cmd_clean. Eleven call sites, one commit, done. Not a single line of logic changed.

What makes this kind of problem sneaky: it's invisible on one machine but can explode on another. My laptop happens to run Docker Desktop, whose compatibility symlink rescues old scripts. On a clean CI runner with only Docker Engine and the compose plugin, the docker-compose command doesn't exist at all. A script that looks healthy today can die tomorrow for no change of its own, just a different environment. That makes a tiny migration very cheap compared with hours of debugging a pipeline that died on its own.

Why the command became two words

Compose v2 was announced in 2020, rewritten in Go, and is no longer a separate program but the official CLI plugin inside docker itself [1]. That's why the command is docker compose: two words, a subcommand of the Docker CLI. There is no new docker-compose binary to install.

The file format got different treatment, too. Compose v2 ignores the version element at the top of compose.yaml and follows the Compose Specification [1]. So the "version is obsolete" warning is expected behavior, not a bug. Old files that still carry a version: 3.8 block still get read; only that element itself is ignored.

The irony of the package name

The funniest part: on Linux the package is still called docker-compose-plugin [3]. The hyphen that vanished from the command landed in the package name. No wonder the docs tell you to run apt-get install docker-compose-plugin while your daily command is docker compose.

After installing, the official docs verify with docker compose version [3]. That little habit travels well when auditing old scripts: if the two-word command answers with a version number, what's running is v2 or newer, not the long-retired Python Compose v1. Auditing your own repo takes ten seconds: grep -rn "docker-compose" --include="*.sh" . from the project root. If it shows up, don't panic; swap the hyphen for a space.

The next version isn't moving house again

The standard has settled. Compose v5, released in 2025, is functionally identical to v2 and keeps the docker compose command [1]. So the script I cleaned up today shouldn't need another migration for the visible future. Compose V1 itself was left behind long ago: official support ended after June 2023 [2], and it has since been removed from Docker Desktop.

If your repo still has docker-compose in its dev scripts, it's not an alarm. But three years without support isn't a comfortable thing to sleep on, either. One small commit, no drama.

Sources

[1] https://docs.docker.com/compose/intro/history
[2] https://www.docker.com/blog/new-docker-compose-v2-and-v1-deprecation
[3] https://docs.docker.com/compose/install/linux

Related articles