01Why Migrate to Docker Compose?
If you've been running Docker containers with long docker run commands, you know the pain: scrolling through bash history to find the right command, forgetting which flags you used, and trying to remember exact volume paths.
I maintained a text file with 30+ docker run commands for two years before switching to Docker Compose. The migration took a single afternoon, and I haven't used docker run for a persistent service since.
Docker Compose gives you version-controlled, reproducible, self-documenting infrastructure. Instead of a 200-character command, you have a readable YAML file anyone can understand.
02The Translation Pattern
Every docker run flag maps directly to a Docker Compose property. Here's a real example:
[terminal]
1# This docker run command:2docker run -d \3 --name nextcloud \4 --restart unless-stopped \5 -p 8080:80 \6 -v nextcloud_data:/var/www/html \7 -e POSTGRES_HOST=db \8 -e POSTGRES_PASSWORD=secret \9 --network my_network \10 nextcloud:2903Becomes Clean YAML
The same configuration in Docker Compose:
[docker-compose.yml]
1services: 2 nextcloud: # --name3 image: nextcloud:29 # image name4 restart: unless-stopped # --restart5 ports: 6 - "8080:80" # -p7 volumes: 8 - nextcloud_data:/var/www/html # -v9 environment: # -e10 - POSTGRES_HOST=db11 - POSTGRES_PASSWORD=secret12 networks: # --network13 - my_network1415volumes: 16 nextcloud_data: 1718networks: 19 my_network: Use 'docker compose convert' to validate your compose file syntax. It shows the fully resolved configuration with all defaults filled in.
04Complete Flag Reference
Common docker run flags and their Compose equivalents:
--name → service key (or container_name)
-d → default in Compose
-p 8080:80 → ports: ["8080:80"]
-v /host:/container → volumes: ["/host:/container"]
-e VAR=value → environment: [VAR=value]
--env-file → env_file: [.env]
--network → networks: [name]
--restart → restart: unless-stopped
--memory 512m → deploy.resources.limits.memory: 512M
--cpus 1.5 → deploy.resources.limits.cpus: "1.5"
--user 1000:1000 → user: "1000:1000"
--read-only → read_only: true
--privileged → privileged: true
--cap-add/drop → cap_add/cap_drop
The biggest Compose advantage is depends_on with health checks, which has no docker run equivalent. You can ensure databases are ready before starting applications. Browse our full-stacks category for multi-container examples.