Docker Run to Compose

Convert docker run commands to docker-compose.yml instantly. Supports ports, volumes, environment variables, networks, restart policies, and more.

  • Runs in your browser
  • Your data never leaves your browser
  • Free · No Sign-Up
Convert the current command to Compose YAML. Review unconverted options in the status and first-line comment. Ctrl/⌘+Enter also converts.
Replace the input with an Nginx example using a name, port, bind mount, environment variable and restart policy, then convert it.
Clear the command, generated YAML and status. Ctrl/⌘+L with focus in the tool does the same.
Enter one docker run or docker container run command. Backslash line continuations are supported. Commands and shell variables are not executed or expanded.
docker-compose.yml
Copy the complete displayed YAML, including any unconverted-options comment. Save it as docker-compose.yml in your project. Empty output is not copied.

Enter a docker run command or load the example to generate Compose YAML.

Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.

Common Use Cases

  • Migration: Turn one-off docker run commands into reproducible compose configurations.
  • Documentation: Convert run commands from README files or docs into compose format for your team.
  • Multi-service setup: Generate individual service blocks and combine them into a single compose file.
  • CI/CD: Replace fragile shell scripts of docker run commands with a declarative compose file.

Example: A PostgreSQL Container

Input:

docker run -d \
  --name postgres \
  -e POSTGRES_DB=myapp \
  -e POSTGRES_USER=admin \
  -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  --restart unless-stopped \
  postgres:16-alpine

Output:

services:
  postgres:
    image: "postgres:16-alpine"
    ports:
      - "5432:5432"
    volumes:
      - "pgdata:/var/lib/postgresql/data"
    environment:
      - "POSTGRES_DB=myapp"
      - "POSTGRES_USER=admin"
      - "POSTGRES_PASSWORD=secret"
    restart: unless-stopped

volumes:
  pgdata:

pgdata is a named volume, so it is declared under the top-level volumes: key. Without that block Compose rejects the file: docker compose config reports service "postgres" refers to undefined volume pgdata. -d is dropped because you detach with docker compose up -d. --name becomes the service key; add container_name: yourself if scripts depend on the exact container name.

Example: Ports, Limits, and an Existing Network

docker run --rm -it --network app-net -p 127.0.0.1:8080:80/tcp \
  --restart on-failure:3 --memory 512m --cpus 1.5 --cap-add NET_ADMIN \
  ghcr.io/acme/web:1.2 npm start
services:
  acme_web:
    image: "ghcr.io/acme/web:1.2"
    ports:
      - "127.0.0.1:8080:80/tcp"
    networks:
      - app-net
    restart: "on-failure:3"
    cap_add:
      - NET_ADMIN
    stdin_open: true
    tty: true
    deploy:
      resources:
        limits:
          memory: 512m
          cpus: "1.5"
    command: ["npm", "start"]

networks:
  app-net:
    external: true

With no --name, the service key comes from the image (ghcr.io/acme/web:1.2 → acme_web). -it is the short options -i and -t together; they become stdin_open and tty. --rm is dropped. --network becomes an external network, so it must already exist (docker network create app-net). --network host, none, bridge, and container:NAME become network_mode: instead.

Example: Options Without a Compose Key

docker run -d --name web --env-file .env --entrypoint /bin/sh -u 1000:1000 -w /app --gpus all nginx:1.27 -c "nginx -g 'daemon off;'"
# Not converted: --gpus all
services:
  web:
    image: "nginx:1.27"
    entrypoint: ["/bin/sh"]
    env_file:
      - .env
    user: "1000:1000"
    working_dir: /app
    command: ["-c", "nginx -g 'daemon off;'"]

--entrypoint takes one executable in docker run, so it becomes a one-item list; the arguments after the image are the command. --gpus has no single Compose key (GPUs are reserved under deploy.resources.reservations.devices), so the converter reads its value, keeps the image name right, and lists it in the first-line comment and the status line.

Every output above passes docker compose config (Docker Compose 5.1); the tool’s test suite runs that check on each example.

Flag Mapping

docker rundocker-compose.yml
-p, --publishports:
-v, --volumevolumes:; named volumes also in the top-level volumes:
-e, --env, --env-fileenvironment:, env_file:
--networknetworks: plus a top-level external: true network; host, none, bridge, container:… become network_mode:
--entrypointentrypoint: (one-item list)
-u, -w, -h, --domainnameuser:, working_dir:, hostname:, domainname:
--restart, --pull, --platformrestart:, pull_policy:, platform:
-l, --label, --annotationlabels:, annotations:
--add-host, --dns, --dns-option, --dns-search, --link, --exposeextra_hosts:, dns:, dns_opt:, dns_search:, links:, expose:
--cap-add, --cap-drop, --privileged, --security-opt, --devicecap_add:, cap_drop:, privileged:, security_opt:, devices:
--init, --read-only, -i, -tinit:, read_only:, stdin_open:, tty:
--tmpfs, --volumes-from, --shm-size, --sysctltmpfs:, volumes_from:, shm_size:, sysctls:
--memory, -m, --cpusdeploy.resources.limits
--memory-reservation, --memory-swap, --cpu-shares, --cpuset-cpus, --pids-limitmem_reservation:, memswap_limit:, cpu_shares:, cpuset:, pids_limit:
--pid, --ipc, --uts, --userns, --cgroupns, --stop-signalpid:, ipc:, uts:, userns_mode:, cgroup:, stop_signal:
--nameservice key
-d, --rm, -q, --detach-keysdropped
image and the arguments after itimage: and command: (JSON array)

Options can be written as --flag value, --flag=value, -p 80:80, -p80:80, or grouped (-dit, -dp 80:80), as the Docker CLI accepts.

Options to Add by Hand

These are read but not converted, because the Compose key has a different shape (services reference):

docker runCompose key
--health-cmd "curl -f http://localhost/" and the other --health-*healthcheck: { test: ["CMD-SHELL", "curl -f http://localhost/"] }
--log-driver, --log-optlogging: { driver: …, options: { … } }
--network-alias api, --ipnetworks: { app-net: { aliases: [api], ipv4_address: … } }
--mountthe long syntax of volumes: (type, source, target)
--gpusdeploy.resources.reservations.devices
--ulimit nofile=1024:2048ulimits: { nofile: { soft: 1024, hard: 2048 } }
--stop-timeout 30stop_grace_period: 30s

Limits

  • One docker run command per conversion. For several containers, convert each one and put the service blocks under a single services: key.
  • docker run and docker container run are recognised; podman run is not.
  • Shell features such as $(...), $VAR, and && are kept as literal text. Expand variables before converting, or use Compose interpolation in the result.
  • Relative bind paths such as ./data are relative to the compose file’s directory in Compose, and to the current directory in docker run.

FAQ

What docker run flags are supported?

It reads every option that docker run accepts (Docker CLI 29.4). About 60 of them have a Compose key and are converted: ports, volumes, environment, env_file, entrypoint, user, working_dir, networks, restart, labels, extra_hosts, cap_add, devices, tmpfs, and more; see the mapping table. The rest are listed as not converted.

What compose file version is generated?

It writes no version key. The Compose Specification treats the top-level version field as obsolete, and Docker Compose v2 only prints a warning when it is present.

How is the service name derived?

If you use --name in your docker run command, that value is used as the service name (no container_name is written). Otherwise, the service name is derived from the image name by stripping the registry prefix and tag, and replacing slashes with underscores.

Does it support multi-line docker run commands?

Yes. Paste commands with backslash line continuations and the converter handles them correctly.

What happens to options without a Compose key?

Their value is still read, so the image name stays correct. They are listed in the status line and in a comment on the first line of the file (for example # Not converted: --gpus all), so you can add the matching Compose settings by hand. An option that docker run does not know is an error, as it is in docker run.

Are named volumes declared?

Yes. A -v source that is a name, such as pgdata:/var/lib/postgresql/data, is added to a top-level volumes: section. Paths that start with /, ., or ~ are bind mounts and are not declared.