Skip to content
DevOps2026-09-103 min read

docker run to docker-compose: The Complete Migration Guide (with Flag Map)

Why bother moving docker run to compose

A service launched with docker run -d --name web -p 8080:80 -v ... keeps its configuration only in the command you typed and your memory. Rebuild on another machine, six months later, or hand over to a colleague — you're archaeology-ing through shell history. Compose turns all of it into a version-managed YAML file:

| Raw docker run | docker compose | |---|---| | Config lives in shell history | Config lives in docker-compose.yml, tracked in git | | Multi-container startup order by hand | depends_on declares it | | Rebuild = rm + retype the long command | docker compose up -d is idempotent | | Half-stopped services cleaned from memory | docker compose down cleans everything | | Ports/volumes scattered | One file shows the whole picture |

Convert in thirty seconds

Paste the docker run command into the docker run to Compose converter, save the result, and run:

docker compose up -d

The conversion runs entirely in your browser — commands containing passwords or internal hosts never leave your machine.

The flag-by-flag map

| docker run | docker-compose.yml | Notes | |---|---|---| | nginx:1.25 | image: nginx:1.25 | image | | --name web | container_name: web (or omit for service name) | Omitting is preferred | | -p 8080:80 | ports: ["8080:80"] | quote port pairs in YAML | | -v ./site:/usr/share/nginx/html | volumes: ["./site:/usr/share/nginx/html"] | bind mount | | -v cache:/var/cache | volumes: ["cache:/var/cache"] | named volume (declare at top level too) | | -e TZ=UTC | environment: ["TZ=UTC"] | env var | | --env-file .env | env_file: [.env] | env file | | --restart always | restart: always | restart policy | | --network mynet | networks: [mynet] + top-level block | custom network | | --network host | network_mode: host | special networks use network_mode | | -u 1000:1000 | user: "1000:1000" | run user | | -w /app | working_dir: /app | working dir | | --entrypoint "sh -c ..." | entrypoint: ... | entrypoint | | -m 512m | mem_limit: 512m | memory limit | | --cpus 1.5 | cpus: "1.5" | CPU limit | | command after image | command: ... | container command |

Three classic pitfalls

1. Bare -e passthrough can't convert

docker run -e DEBUG nginx   # references the HOST's DEBUG variable

A compose file is static and can't express "reference a host variable". Write it fully as -e DEBUG=value, or move everything to env_file.

2. Anonymous volumes have no equivalent

docker run -v /var/log nginx (container path only) creates an anonymous volume; compose needs a named volume or a bind path. The converter lists it in the warnings area — give it a name (logdata:/var/log) and declare it in the top-level volumes block.

3. --rm changes meaning

In raw run, --rm means "delete the container on exit"; compose manages the lifecycle via down and neither needs nor supports --rm. Not a lost feature — a different model.

Multi-container: wire dependencies after converting

After converting each docker run into a service, add the dependency graph:

services:
  app:
    image: myapp:2.0
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 10

The service_healthy condition (compose v2.20+) solves the classic "app starts before the database is ready" race — the problem raw run solved with sleep scripts.

FAQ

Q: Does the generated file need a version field? No. Modern docker compose (v2 CLI) deprecates version and warns when present. The converter emits the modern format.

Q: Must the file be named docker-compose.yml? compose.yaml / docker-compose.yml are picked up by default; use -f for anything else: docker compose -f prod.yml up -d.

Q: Will up conflict with already-running containers? Yes — same-name conflicts (container name already in use, see this guide). docker stop/rm the old container first, or rename the service for transition. Port conflicts: port already allocated.


Provided by ToolVault. Related tools: docker run to Compose converter, Dockerfile Generator, Linux Cheatsheet. Related reading: Container name conflicts, Port already allocated. See the homepage for more developer tools.


Advertisement