Docker Run vs. Docker Compose
· 3 min read
At some point, every beginner runs into this question:
Should I use
docker run, or should I use Docker Compose?
The practical answer is simple:
- Use
docker runwhen you want to start one container quickly - Use Docker Compose when you want to define and manage one or more containers as a reusable setup
You can think of it like this:
docker run= one command, typed by handdocker compose= a saved recipe in adocker-compose.ymlfile
When to use each one
| Use case | Better choice |
|---|---|
| Quick test | docker run |
| Learning basic flags | docker run |
| Reusable setup | Docker Compose |
| Multi-container app | Docker Compose |
| Team sharing | Docker Compose |
| Easier updates | Docker Compose |
Visual difference
flowchart LR
A[docker run] --> B[One command typed manually]
B --> C[One container starts]
D[docker compose] --> E[YAML file defines services]
E --> F[One command starts full stack]
Install Docker Compose
If you installed Docker Desktop, Compose is already included as docker compose.
If you want to install it explicitly:
winget install -e --id Docker.DockerCompose
Verify:
docker compose version
Simple example with docker run
docker run -d `
--name my-nginx `
-p 8080:80 `
--restart unless-stopped `
nginx
Parameters explained
-d→ run in background--name→ container name-p→ port mapping (host:container)--restart→ restart policynginx→ image
Open: http://localhost:8080
Same setup with Docker Compose
services:
nginx:
image: nginx
container_name: my-nginx
ports:
- "8080:80"
restart: unless-stopped
Run:
docker compose up -d
Why Compose is better here
- No need to remember long commands
- Easy to edit and reuse
- Shareable config
- Cleaner structure
Advanced example — Portainer (docker run)
docker volume create portainer_data
docker run -d `
--name portainer `
-p 9000:9000 `
--restart always `
-v /var/run/docker.sock:/var/run/docker.sock `
-v portainer_data:/data `
portainer/portainer-ce
Parameters explained
docker volume create→ persistent storage-v host:container→ mount volume/var/run/docker.sock→ allows Portainer to control Dockerportainer_data:/data→ saves app data--restart always→ auto restart
Same Portainer setup with Docker Compose
services:
portainer:
image: portainer/portainer-ce
container_name: portainer
ports:
- "9000:9000"
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
volumes:
portainer_data:
Run:
docker compose up -d
docker compose commands
Start
docker compose up
Start (background)
docker compose up -d
Stop & remove
docker compose down
Remove including volumes
docker compose down -v
Restart
docker compose restart
Stop only
docker compose stop
Start stopped services
docker compose start
Status
docker compose ps
Logs
docker compose logs
Follow logs
docker compose logs -f
Pull updates
docker compose pull
Rebuild
docker compose up --build
Force recreate
docker compose up -d --force-recreate
Remove orphan containers
docker compose up -d --remove-orphans
Restart policies
In docker run:
--restart always
In Compose:
restart: always
Types
noalwaysunless-stoppedon-failure
Final takeaway
- Use
docker runfor quick tests - Use Docker Compose for anything you want to keep
That’s the real difference.