What is supported
Ports, volumes (-v and --mount: bind, volume, tmpfs), env vars and --env-file, --restart, networks with aliases and fixed IPs, healthcheck, logging, memory and CPU limits, --gpus, ulimit, sysctl, capabilities, devices, --entrypoint and the command after the image. Named volumes go to the volumes section, custom networks to networks. No version key is added: it is obsolete in Compose v2.
After converting
Check the result with docker compose config — it prints the final configuration with variables filled in. Move passwords from -e into a .env file next to compose.yaml, reference them as ${DB_PASSWORD}, and keep .env out of git.
FAQ
Which docker run flags are not converted?
Those with no Compose equivalent: --rm, -P (--publish-all), --cidfile, --sig-proxy, --label-file and similar. They are listed under the result. -d is not needed: docker compose up -d runs services in the background.
Why are networks marked external: true?
A custom network in docker run (--network backend) already exists and was created by hand. With external: true Compose attaches to it instead of creating a new one with the project prefix. Drop external if the network should belong to the project.
What about $HOME and passwords containing $?
Variables that were unquoted or in double quotes stay variables — Compose fills them from the environment or .env. A $ that was literal in the shell (single quotes or escaped) is written as $$ so Compose does not interpolate it.
Why does the reverse conversion create an app_default network?
Compose puts services on a shared project network where they resolve each other by name. Plain docker run uses the bridge network without name resolution, so for several services a docker network create and --network are added to keep links such as db:5432 working.
