Docker Compose Converter
Convert a docker run command into the equivalent docker-compose.yml service block. Handles ports, volumes, env, restart, networks, healthcheck.
Docker Compose Converter Tool
version: "3.8"
services:
example:
image: nginx:alpine
ports:
- "8080:80"
restart: unless-stopped
Known issue: the output opens with version: "3.8". The Compose Specification
lists that key as obsolete — it is kept for backward compatibility
and current Compose prints a
warning when it sees one. Delete the first line before you commit the file; nothing else in the output
depends on it.
How to use the Docker Compose converter
Paste your docker run command
Single-line or multi-line with \ continuation — both formats work. The tool tokenises the command, identifies flags, and builds the equivalent compose service.
Review the output
The right pane shows a complete docker-compose.yml with the standard services: block. Volumes and networks declared via shorthand are promoted to top-level volumes: and networks: sections automatically.
Watch for the warnings
Two things land in the yellow box. A flag the parser knows takes an argument but does not yet translate is reported by name, so you can add it by hand; an unrecognised flag is reported as skipped. On top of that, --rm always produces a note, because it is the one common flag with no service-level equivalent at all — a long-running Compose service cannot be told to delete itself on exit. Flags that only affect an interactive session (-d, -i, -t) are consumed silently, since they describe how you invoked the container rather than what it is.
Copy or download
Copy the YAML or download it as docker-compose.yml, put it at your project root, and run docker compose up -d. One line is worth deleting first: the output opens with version: "3.8", and current Compose treats that key as obsolete — see the note below the converter. The file runs either way; you will just see a warning until you remove it.
Docker Compose — when one container becomes a stack
docker run is fantastic for "give me one container, now." It runs nginx in front of a static site, spins up postgres for testing, or boots a quick redis for a benchmark. It stops being adequate the moment your application needs multiple services that need to know about each other. The classic three-tier — a web app, a database, a cache — is three docker run commands you have to remember to run in the right order, with manually-typed network names so the services can find each other, and manually-managed restart-on-reboot scripts so the whole thing comes back up after a server reboot. Docker Compose collapses all of that into one YAML file plus one command.
The compose YAML you actually need
A useful docker-compose.yml has three top-level keys: services: (the containers themselves), volumes: (named persistent storage), and networks: (custom bridge networks for service-to-service communication). Inside each service: image: (which image to run), ports: (host:container port mappings), environment: (env vars), volumes: (mounts), restart: (policy), and depends_on: (startup ordering). That's it for 90% of real-world usage. The tool above translates a single docker run into exactly this minimal-but-complete structure.
The version key, and why this converter still writes one
"Compose v2" is two different things, which is most of why this subject is confusing. It is the name of the file format that introduced the version: '2.x' header, and it is also the name of the Go rewrite of the command — the one you invoke as docker compose rather than docker-compose. They are unrelated numbers.
The file-format numbers are the part that has been retired. There is now one document, the Compose Specification, and it is explicit about the header: the top-level
It is not used for validation either — version property is defined by the Compose Specification for backward compatibility. It is only informative you'll receive a warning message that it is obsolete if used.Compose doesn't use
version to select an exact schema to validate the Compose file, but prefers the most recent schema when it's implemented.
This converter nevertheless emits version: "3.8" as the first line of its output. That is a defect rather than a design choice, and it is recorded as one; until it is fixed, delete that line before you commit the file. Nothing else in the generated YAML depends on it, and removing it silences the obsolescence warning.
What docker run flags don't map to compose
Most map one-to-one, and the exceptions are worth naming. --rm has no service-level equivalent: a Compose service describes something that is meant to exist, so the closest you get is docker compose run --rm <service> for a one-off. --name becomes the service name, which is the name other services resolve over the network; the separate container_name: key sets the literal container name, and the specification warns that it forecloses scaling — Compose does not scale a service beyond one container if the Compose file specifies a
container_name. Attempting to do so results in an error.--init and --privileged become the boolean keys init: true and privileged: true, and this converter writes both. --cap-add NET_ADMIN becomes cap_add: [NET_ADMIN]. Flags in the parser's known-argument list that it does not yet translate — --device, --ulimit, --dns, --add-host, --memory, --cpus, --label, --entrypoint — are reported by name rather than dropped, so nothing disappears quietly.
From compose to Kubernetes
kompose, a Kubernetes SIG-Apps project, converts a docker-compose.yml into Deployment and Service manifests. Expect the translation to be lossy in specific, predictable ways: depends_on has no Kubernetes counterpart because pods do not have an ordering primitive, healthchecks map onto liveness and readiness probes that behave differently from Compose's single check, and resource limits use a different syntax entirely. For a small stack it produces a starting point rather than a finished manifest.
Production gotchas worth knowing
Three catch people out. Every service in the file shares one default network, so any container can reach any other by service name — fine in development, not an isolation boundary. Declare named networks and attach services deliberately if you need one. Relative paths resolve against the Compose file, not your shell. The specification says so for env_file — relative path are resolved from the Compose file's parent folder
— and warns that an absolute path makes the file non-portable; the same care applies to bind mounts, which is why a named volume is the safer choice for anything that must survive. And short-form depends_on waits for start, not for readiness. The long form is what you want: condition: service_healthy against a dependency that defines a healthcheck:, or service_completed_successfully for a migration container that must finish before the app boots.
Compose Specification rules this converter's output has to live with
There is no longer a "compose v3" schema to target. The Compose Specification is one living document; Compose doesn't use
Choosing a format version is a decision that no longer exists.version to select an exact schema to validate the Compose file, but prefers the most recent schema when it's implemented.
The version: key is obsolete, and the converter still writes it. The specification: it is defined by the Compose Specification for backward compatibility. It is only informative you'll receive a warning message that it is obsolete if used.
Delete the first line of the output; nothing else depends on it.
Service-to-service hostname resolution works automatically — postgres:5432 from the app container resolves to whatever IP the postgres service is on, via Docker's embedded DNS.
Named volumes (volumes: { pgdata: }) persist across docker compose down and up. Anonymous volumes (no name) get garbage-collected on every down.
Short-form depends_on waits for started, not ready. The long form takes three conditions: service_started, service_healthy (needs a healthcheck: on the dependency), and service_completed_successfully — the last being the one that makes a migration container work.
environment: beats env_file: — and the specification closes the obvious loophole: values in environment override the file even if those values are empty or undefined
. Listing a variable with no value therefore blanks it rather than falling through.
docker compose up --build rebuilds images defined with a build: directive. Without --build, compose reuses the cached image — a common reason "my code changes aren't showing."
Setting container_name: costs you scaling. The specification: Compose does not scale a service beyond one container if the Compose file specifies a
Which is why container_name. Attempting to do so results in an error.--name becomes the service name here, not a container name.
Compose secrets (top-level secrets: block) mount file-based secrets into containers without exposing them in environment variables — better than environment: { DB_PASS: ... } for production.
A relative path in a Compose file resolves against the file, not your shell. The specification states it for env_file — relative path are resolved from the Compose file's parent folder
— and warns that absolute paths prevent the Compose file from being portable
. The same reasoning is why a named volume beats a bind mount for anything durable.
Frequently asked questions
--name, -p/--publish, -v/--volume, -e/--env, --env-file, --restart, --network, --depends-on, the five --health-* flags, --cap-add, --cap-drop, --privileged, --init, --user/-u, --workdir/-w and --hostname/-h, plus the image and any command after it. Consumed and ignored, because they describe the invocation rather than the service: -d, -i, -t, -it. Reported in the warnings box rather than translated: --rm, and --label/-l, --memory/-m, --cpus, --device, --ulimit, --add-host, --dns and --entrypoint, each named so you can add it by hand.version: "3.8" line is the reason it still works with the older one. Under the current Compose Specification that key is obsolete and produces a warning — it is only informative you'll receive a warning message that it is obsolete if used— so on a modern
docker compose you should delete it. The rest of the generated file uses keys the specification defines, with no version-gated syntax in it.-v pgdata:/var/lib/postgresql/data) are added to a top-level volumes: block in addition to the service mount. Bind mounts (e.g. -v ./html:/usr/share/nginx/html) stay as inline service-level mounts only.services: section.docker compose run --rm <service> for one-off commands, but the long-running service definition itself has no --rm setting.--health-cmd, --health-interval, --health-timeout, --health-retries, and --health-start-period all map to the healthcheck: block in the service.--network, the named network is added to a top-level networks: block and the service is attached to it. If no network is specified, the service uses compose's automatic default network — which is fine for most cases.depends_on with a readiness condition, a shared network, a named volume two services mount — and a docker run command describes one container in isolation. Anything a Compose file says about how services relate has nowhere to go.Related News
You may be interested in these recent stories from our newsroom.
-
OpenAI's Agents Attacked RubyGems in May. Nobody Told RubyGems.
A swarm uploaded 2,000 packages, went after user API keys and abused the documentation builder. The volunteers who closed sign-ups for four...
-
Attackers Are Minting Artifactory Admin Tokens. The Log Says Anonymous.
Two flaws chain an unauthenticated request into administrator scope in under five minutes, and the audit trail records the actions without n...
-
GitLab Patched a 10.0 File-Read Flaw. Probes Appeared the Next Day.
An unauthenticated attacker could read any file on a self-managed server. What sits on that server is every credential the build system can...
Method & sources
How it computes
Tokenises a `docker run` command in the browser, maps each flag to the corresponding Compose Specification service key, and assembles a docker-compose.yml. Named volumes and explicit networks used in the command are promoted to top-level volumes: and networks: blocks. Flags that describe the invocation rather than the service (-d, -i, -t) are consumed; flags it does not translate are reported by name in a warnings box rather than dropped.
What this tool implements
- Output keys are the Compose Specification's: services, volumes, networks, and per service image, container/service naming, ports, environment, env_file, volumes, restart, depends_on, healthcheck, cap_add, cap_drop, privileged, init, user, working_dir and hostname.
- ⚠️ The converter emits a top-level `version: "3.8"`, which the Compose Specification lists as obsolete: it 'is defined by the Compose Specification for backward compatibility. It is only informative you'll receive a warning message that it is obsolete if used.' This is a DEFECT, not a compatibility choice. It is not silently excused on the page — a Known issue note sits directly under the converter, the how-to tells the reader to delete the line, and fact 02 quotes the specification.
- The page no longer offers a format version to choose, because the specification removed the choice: 'Compose doesn't use version to select an exact schema to validate the Compose file, but prefers the most recent schema when it's implemented.'
- depends_on is described in both forms: the short form waits for started, and the long form's three conditions are named — service_started, service_healthy (which requires a healthcheck on the dependency) and service_completed_successfully.
- env_file precedence is quoted with the part that surprises people: environment values override env_file values 'even if those values are empty or undefined'.
- container_name is described with its documented cost: 'Compose does not scale a service beyond one container if the Compose file specifies a container_name. Attempting to do so results in an error.' That is why --name becomes the service name here.
Sources
- The Compose Specification, compose-spec/compose-spec — the normative document for every key the converter emits: the obsolete top-level version property, the top-level name property, container_name and its scaling constraint, depends_on short and long syntax with service_started / service_healthy / service_completed_successfully, and env_file precedence and path resolution: https://github.com/compose-spec/compose-spec/blob/main/spec.md
- Docker CLI reference, docker run — the flag set the parser accepts and the semantics of --rm, --init, --privileged, --cap-add and the --health-* family: https://docs.docker.com/reference/cli/docker/container/run/
- Docker Compose documentation, Compose file reference — the rendered form of the specification, including the obsolescence warning emitted for a version key: https://docs.docker.com/reference/compose-file/
- kompose, Kubernetes SIG-Apps — the compose-to-Kubernetes converter named in the Kubernetes section: https://kompose.io/
What can make this go out of date
- None at runtime. Parsing and YAML generation happen in the page; the command and the generated file are never transmitted.
- The Compose Specification is a living document with no version number, so a key that is current today can be marked obsolete without a release to point at — which is exactly what happened to the version key this tool still writes.
Abridged — the full review record for this tool runs longer than the list above.
Pick up where you left off
Stored only in this browser — never sent to our servers.