docker run creates and starts containers. Everything that happens after — listing them, stopping them, restarting them, getting rid of them — is the container lifecycle. This article covers the small set of commands that handle all of that: docker ps, docker stop, docker start, docker restart, docker rename, docker rm, plus kill, pause, and the auto-remove --rm pattern.
The lifecycle states
A container moves between these states:
created → running → paused → running → exited → removed
↘ exited ↗
- created —
docker createran but the container hasn't been started. Rare; usually you go straight to running withdocker run. - running — the main process is alive.
docker psshows it. - paused — frozen via cgroups.
docker pauseanddocker unpause. - exited — the main process has stopped (either gracefully via
docker stopor because it crashed/finished). The container still exists; you can read logs, inspect, restart. - removed — the container's filesystem and metadata are gone.
docker rmdid this.
List running containers — docker ps
# Running containers
docker ps
# All containers, including stopped ones
docker ps -a
# Just the IDs (useful in scripts)
docker ps -q
# All IDs (running + stopped)
docker ps -aq
# Filter by status, name, image, label
docker ps --filter status=exited
docker ps --filter name=web
docker ps --filter ancestor=nginx:alpine
docker ps --filter label=env=production
# Custom format with Go templates
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
# Show file sizes (writable layer + image)
docker ps -sdocker ps is the inventory command. By default it only shows running containers; add -a to see everything including exited ones — that's how you find the container that died ten minutes ago so you can docker logs it.
The default columns are container ID, image, command, age, status, ports, and name. --format lets you pull just the columns you want; useful in scripts.
Stop a container — docker stop
docker stop CONTAINER_NAME
# Custom grace period (default is 10s)
docker stop -t 30 CONTAINER_NAME
# Stop all running containers
docker stop $(docker ps -q)docker stop sends SIGTERM to the container's main process, waits 10 seconds for it to exit gracefully, then sends SIGKILL if it hasn't. The 10-second wait is the most common reason a docker stop "feels slow" — your app isn't reacting to SIGTERM, so Docker waits the full timeout before killing.
Two ways to fix that:
- Use exec form for CMD/ENTRYPOINT in your Dockerfile. Shell form (
CMD npm start) wraps your process in/bin/sh -c, which receivesSIGTERMbut doesn't pass it to your app. Exec form (CMD ["npm", "start"]orCMD ["node", "server.js"]) sends signals directly. See How to Write a Dockerfile. - Handle
SIGTERMin your app. Express, Fastify, FastAPI etc. all have graceful-shutdown patterns. Without one, your app gets killed mid-request.
docker kill CONTAINER_NAME skips the SIGTERM and sends SIGKILL immediately. Useful when an app is wedged and stop is taking too long.
Start and restart a stopped container — docker start, docker restart
# Start a stopped container (keeps the same name, same volumes, same env)
docker start CONTAINER_NAME
# Start AND attach my terminal to it
docker start -a CONTAINER_NAME
# Restart (stop + start)
docker restart CONTAINER_NAME
# Restart with custom grace period
docker restart -t 30 CONTAINER_NAMEA stopped container is not gone. docker start brings it back exactly as it was — same name, same network attachments, same volumes mounted, same env. This is the difference between docker start and docker run: run always creates a new container; start resurrects an existing one.
When to use which:
docker restartwhen a service is misbehaving and you want to reset it without losing its config. Database isn't responding to queries; bounce it.docker startwhen you previously stopped a container and want it back. Common after host reboots if you don't have a--restartpolicy set.docker runwhen you want a fresh container, possibly with different flags.
Restart policies — surviving crashes and reboots
If you want a container to come back automatically after a crash or a host reboot, set a restart policy:
docker run -d --restart unless-stopped CONTAINER_NAME IMAGE_NAME| Policy | Behavior |
|---|---|
no (default) | Never restart. |
on-failure[:max] | Restart only on non-zero exit. Optional max-attempts. |
always | Restart, including after host reboot. Restarts even if you manually stopped it. |
unless-stopped | Restart, including after host reboot. Does NOT restart if you stopped it manually. |
unless-stopped is the right default for almost every long-running service. Full breakdown plus health-check pairing in Docker Restart Policies and Health Checks.
Pause and unpause — docker pause
docker pause CONTAINER_NAME
docker unpause CONTAINER_NAMEpause uses the cgroups freezer to suspend every process inside the container. It is not the same as stop — the processes are still there, they just aren't scheduled. Memory is preserved. Useful for snapshotting / quiescing state without a full restart.
Not commonly needed in day-to-day work. The two cases I've actually used it: pausing a CPU-hungry container to let another finish first, and pausing a database briefly while taking a filesystem snapshot of its volume.
Rename a container — docker rename
docker rename OLD_NAME NEW_NAMEJust changes the name. The container ID, volumes, network attachments, everything else stays the same. Useful when you started with --name old_temp and want to give it a real name without recreating.
Remove a container — docker rm
# Remove a stopped container
docker rm CONTAINER_NAME
# Force-remove (stops it first if running)
docker rm -f CONTAINER_NAME
# Remove a container AND its anonymous volumes
docker rm -v CONTAINER_NAME
# Remove all stopped containers in one go
docker container prune
# Remove ALL containers (running and stopped) — destructive
docker rm -f $(docker ps -aq)docker rm deletes the container's filesystem (the writable layer) and metadata. The image is unaffected; you can docker run again from the same image and get a fresh container.
By default, named volumes survive docker rm — that's the whole point of using a named volume. Anonymous volumes (volumes you didn't name, declared by VOLUME in a Dockerfile or just -v /path) survive by default too, but -v (or --volumes) on docker rm removes them. To clean them up later, docker volume prune.
The --rm flag — auto-remove on exit
# Container is deleted the instant its main process exits
docker run --rm IMAGE_NAME
# --rm + -it = the throwaway interactive shell pattern
docker run --rm -it IMAGE_NAME bash--rm is for one-shot containers — try a tool, run a quick command, get an interactive shell to poke around. Without --rm, every quick test leaves a stopped container behind, and a week later docker ps -a is a graveyard.
Do NOT use --rm on services you might want to inspect later. Once the container exits, docker logs is no longer available for it.
Common patterns
Find and stop a container by name pattern:
docker stop $(docker ps -q --filter name=web)Stop everything cleanly:
docker stop $(docker ps -q)Clean up all stopped containers:
docker container prune
# or, with no prompt:
docker container prune -fRestart a container that's stuck:
docker kill CONTAINER_NAME && docker start CONTAINER_NAMEWatch a container's lifecycle events live:
docker events --filter type=container --filter container=CONTAINER_NAMEUseful when debugging a container that keeps restarting — the events show every start, die, restart with timestamps and exit codes.
Common pitfalls
docker stoptaking 10 full seconds every time. Your app isn't handling SIGTERM. Either use exec form in your Dockerfile's CMD, or add a SIGTERM handler in the app. See How to Write a Dockerfile.- "Conflict. The container name '/web' is already in use." A container with that name still exists, even if stopped. Either
docker rm webfirst, ordocker run --rmto auto-clean, or use a different name. docker psdoesn't show my container — butdocker ps -adoes. It's not running. Either it crashed (checkdocker logs) or it exited normally (single-shot command). Restart withdocker start.- Containers piling up over time. Add
--rmto one-shot runs, and periodicallydocker container prune. Or use a restart policy and let Docker manage state. docker rmdoesn't delete the volume. Correct — named and anonymous volumes survive container removal by default. Usedocker rm -vto remove anonymous volumes, anddocker volume pruneto clean up unused ones.
FAQ
Sources
Authoritative references this article was fact-checked against.
- docker container — CLI referencedocs.docker.com

