Docker Run to Compose Converter
Convert docker run commands into a modern compose.yaml with a flag-by-flag conversion report — entirely on this device.
Conversion report
The flag-by-flag report appears here after a conversion.
Press ? for shortcuts
Do it offline:$ npx composerize docker run -d -p 8080:80 --restart unless-stopped nginx:1.27
How to use it
- Paste a docker run command. Line continuations and both quoting styles parse; several commands split on newlines, ; or &&, and conversion runs as you type.
- Read the compose.yaml pane — services are named after their images, and flags the converter does not recognize sit as comments above their service; flags compose cannot express at all appear in the report below.
- Work through the conversion report: every flag you typed appears exactly once, grouped under headings like Ports & networking, Resources, or Not representable.
- Copy or download the file. Turning on .env extraction moves literal -e values into a separate .env, loaded back through env_file.
A docker run command and a compose file describe the same container in two different grammars. Paste one or more run commands to get a services: block back, next to a flag-by-flag report saying where each option went — mapped to a compose key, kept as a comment, or not expressible at all. Backslash continuations, docker create, and podman run convert too, and the command never leaves this device.
Examples
docker run -d -p 8080:80 -v ./html:/usr/share/nginx/html --restart unless-stopped nginx:1.27services:
nginx:
ports:
- 8080:80
volumes:
- ./html:/usr/share/nginx/html
restart: unless-stopped
image: nginx:1.27
The three flags with compose homes land as ports, volumes, and restart keys. -d gets a report row instead: -d has no compose equivalent — services start detached with "docker compose up -d".
docker run -d --name db -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret postgres:17services:
# named volume 'pgdata' is marked as "external" (used by service 'postgres'), so either remove "external" from volume definition or it needs to be created using: docker volume create pgdata
postgres:
container_name: db
volumes:
- pgdata:/var/lib/postgresql/data
env_file:
- .env
image: postgres:17
volumes:
pgdata:
external: true
name: pgdata
With extraction on, the password stays out of compose.yaml — the generated .env carries POSTGRES_PASSWORD=secret, loaded through env_file. The comment is the external-volume warning: run docker volume create pgdata once, or drop external from the volumes block.
docker run -d --name web -p 8080:80 nginx
docker run -d --name cache redis:7services:
nginx:
container_name: web
ports:
- 8080:80
image: nginx
redis:
container_name: cache
image: redis:7
Two commands become two services in one file, and a chip states the consequence: 2 services share this compose file — they join its default network and can reach each other by service name.
docker run -d --network container:web --name sidecar busyboxservices:
busybox:
# --network container:web maps to "network_mode: container:web" — compose does not create or manage that container; make sure "web" is running before "docker compose up" (not a full docker run equivalent).
network_mode: container:web
container_name: sidecar
image: busybox
network_mode: container:web is a passthrough, not a full equivalent — compose will not start or manage the web container. The caveat appears twice on purpose: as the YAML comment and as the report row, so screen readers meet it too.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
What compose deliberately cannot say
Session flags have no file equivalent: -d falls away because docker compose up -d decides detachment at start time, --rm because docker compose down owns removal, -P because compose never publishes all exposed ports itself. Each stays visible as a not-representable report row rather than vanishing.
Two commands with one image merge into one service
Service names come from the image basename, so two nginx commands fold into one nginx service: list values such as ports accumulate, single-value keys like container_name keep the later command's value. Convert same-image commands one at a time when they must stay separate.
A value of 0 can be ignored upstream
The mapping library silently drops flags whose value parses as falsy — --memory-swappiness 0, --cpu-quota 0. Such a flag is downgraded to an unknown report row and kept as a comment, so the report never claims a key the YAML does not contain.
Dollar variables change readers
An unquoted $HOST is expanded by your shell before docker runs; inside compose.yaml, docker compose itself interpolates it from your environment or an .env file. Even a single-quoted variable a shell would keep literal interpolates here — write $$ for a literal dollar.
Windows paths survive, with a portability chip
Drive-letter binds like C:\data:/data come back verbatim under volumes, plus a chip reminding you that host paths are machine-specific — reach for a named volume when the file must run anywhere else.
Digest-pinned images rename their service
An image such as nginx@sha256:… would make an invalid service key, so the service takes the sanitized basename and a chip records the rename. The image line keeps the full digest, pinned exactly as you wrote it.
Common errors
Unclosed quote starting at column 24 on line 1.- The pre-parser reads your command the way a shell would, so an unfinished quote stops conversion before any guessing starts. Columns are 1-based on the pasted line, and Jump to error lands the cursor there — usually a clipped copy lost the closing quote.
This looks like a Dockerfile, not a docker run command — paste a docker run, docker create, podman run, or podman create command.- FROM, RUN, COPY, or ARG at the head of a line reads as a Dockerfile, which builds an image rather than starting a container. Convert the docker run command that launches the finished image — the two kinds do not translate into each other.
Input is larger than the 64 KB limit for this tool. For bigger commands use the CLI: npx composerize docker run -d -p 8080:80 --restart unless-stopped nginx:1.27- The cap refuses outright rather than trimming, so conversion covers your whole input or none of it. 64 KB outruns any real command line; beyond it, the npx line runs the same conversion library from your terminal.
FAQ
What happens to docker run flags that compose cannot express?
They stay visible instead of disappearing: each gets a not-representable report row naming the substitute — detachment moves to docker compose up -d, removal to docker compose down — while flags the converter does not know are kept as comments and reported as unknown.
Can several docker run commands become one compose file?
Yes — statements split on newlines, semicolons, or &&, and each image produces one service on the file's shared default network, reachable by service name. Watch the report when two commands share an image: they merge.
Is podman run or docker create accepted?
Both, as a labeled subset: they convert with the same flag mappings, and a chip names the input kind. Only four spellings are read — docker run, docker create, podman run, podman create — so the long docker container run form is declined.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Re-run the conversion immediately.
- ⌘/Ctrl + S
- Download compose.yaml, overriding the browser's save dialog.
- ⌘/Ctrl + C
- Copy the compose output while no text is selected.
- ⌘/Ctrl + Shift + C
- Copy the whole output even mid-selection.
- t
- Advance the theme.
- ?
- Open the shortcut help overlay.
- Esc
- Dismiss the topmost overlay.