piapia123
en

Compose ↔ docker run

Web

Everything runs locally in your browser — nothing is uploaded

Input
Drop a file here to load its contents
Output

Both directions work: paste a compose `services:` section to get `docker run` commands, or paste a `docker run` command to get a compose snippet. The kind of input is detected automatically. ⚠️ But the two formats are not equally expressive, so the conversion cannot be complete. That is the single most important thing to know before using this: · `depends_on`, `deploy` (replicas, resource limits), `profiles`, `extends` — compose has them, and `docker run` has nothing corresponding. Replicas especially: `docker run` starts exactly one container, and “three replicas” does not exist as a concept in a single command. · `${VAR}` interpolation, the merge order of `env_file` and `.env`, and the base directory for relative paths (the compose file’s directory versus the current directory) — the meaning shifts after conversion, while the result looks entirely reasonable. So the approach here is: convert what maps one-to-one, and list what does not, with the reason. Silently dropping a `deploy` block would suggest that the command is equivalent to the original service when it is not. ⚠️ The other easy trap is argument position in `docker run`: a token starting with `-` after the image is not a docker option, it is an argument to the command inside the container (the `-g` in `docker run nginx -g "daemon off;"` belongs to nginx). Splitting by position means the command survives intact. Everything runs in your browser. Need to plan Docker’s address pools and subnets (the `default-address-pools` / `bip` in `daemon.json`)? That is a separate tool: “Docker Subnet Planner”.

Features

  • Both directions detected automatically: a compose services section ↔ a complete docker run command
  • image, container_name, ports, volumes, environment, env_file, command, entrypoint, restart, network_mode, working_dir, user, hostname
  • Switches: privileged, read_only, tty, stdin_open
  • A healthcheck test array becomes --health-cmd, along with interval, timeout and retries
  • Short and long port forms (target / published / protocol); non-tcp gets its suffix
  • Long volume form (source / target / read_only) becomes `-v src:dst:ro`
  • ⚠️ depends_on, deploy, profiles and extends are listed individually, with the reason there is no counterpart
  • ⚠️ build, multiple networks, named volumes and empty `KEY=` values are flagged as places where the meaning shifts
  • ⚠️ Unrecognised docker options are reported honestly rather than folded into the result
  • ⚠️ Trailing line continuations are handled — commands copied from `docker ps` or the docs all carry them
  • ⚠️ Arguments after the image are split off as the command, so `-g` and friends are not dropped as docker options
  • Runs entirely in your browser

How to use

  1. Paste a compose services section, or a docker run command
  2. Optionally name a single service to convert
  3. Read the command or snippet first, then the “what did not carry over” and “where the meaning shifts” sections

FAQ

Why did some configuration not carry over?
Because it has no counterpart in `docker run`. `deploy` is the clearest case: it configures replica count, resource limits and rolling-update policy, which belong to the orchestration layer, while `docker run` starts one container — “three replicas” simply does not exist in a single command (that takes `docker service` or an orchestrator). `depends_on` (start order) and `profiles` (gating) are the same. Quietly dropping what cannot be expressed suggests the command is equivalent to the original service, and you discover otherwise when you deploy with it.
Why can relative paths end up wrong after converting?
Because the two resolve against different directories: a relative path in compose is resolved against the compose file’s directory, while arguments on a `docker run` command line resolve against the current working directory. The entry `./site:/usr/share/nginx/html` means `/srv/app/site` when the compose file lives at `/srv/app/docker-compose.yml`, and means wherever you happen to be when you run the converted command elsewhere. The command looks identical; it mounts something else.
Why do `-d` and `--rm` disappear?
Because they are not part of a service definition in compose. `-d` (run detached) corresponds to `docker compose up -d`, which is a command-level flag and would be meaningless on an individual service, and `--rm` has no compose service key either. Their absence is correct: in compose terms they should not have been there.
Why was the `-g` after the image not dropped as an option?
Because docker’s grammar is `docker run [OPTIONS] IMAGE [COMMAND]`, and everything after the image is the command run inside the container. The `-g` in `docker run nginx -g "daemon off;"` is an nginx argument, not a docker switch. Splitting by position keeps it in the command; without that, it would be discarded as an unrecognised docker option while the compose file still looked complete.
Can it convert to Podman or Kubernetes?
No — this does compose and `docker run` only. Converting to Kubernetes is a different order of problem: how a Deployment splits into Services, ConfigMaps and Secrets depends on how your cluster is organised, so it is not a one-to-one mapping. YAML produced that way would run, and be hard to maintain.
Where is the daemon.json address pool planning?
In a separate tool, “Docker Subnet Planner”. This one only converts between compose and `docker run`: a service-orchestration file on one side, a single run command on the other. Address pools (`default-address-pools`) and docker0’s `bip` are daemon-level settings with no counterpart in a container’s run command, so they live in their own tool rather than mixing two different jobs on one page.

Related tools