What is a Docker restart policy and what options exist?
Docker restart policies automate container resilience. Crash? The daemon restarts you. Host reboot? Container comes back. The four options trade off control vs. automation differently — pick by what you want the container to survive.
Theory
TL;DR
--restart=<policy>ondocker run(orrestart: <policy>in Compose) sets the policy.- Four values:
no,on-failure[:N],always,unless-stopped. - Production default:
unless-stopped— survives crashes and host reboots, respects manual stop. - Default if not specified:
no— container exits and stays exited. - Restart policies kick in on container exit, regardless of whether the exit was clean (0) or not. Filtering by code is what
on-failureadds.
The four policies
| Policy | On exit (any code) | On exit code 0 | After host reboot | Respects manual stop |
|---|---|---|---|---|
no (default) | no | no | no | n/a |
on-failure[:N] | yes if code != 0, up to N times | no | no (does not survive reboot) | yes |
always | yes | yes | yes | no (restarts even after stop) |
unless-stopped | yes | yes | yes (if was running) | yes |
no — the default
docker run myapp
# Crashes → exited. Stays exited.
# Host reboots → container does not come back.Fine for one-off commands (docker run --rm for a CI job). Wrong for any service you expect to keep running.
on-failure[:N] — restart on crash, up to N times
docker run --restart=on-failure myjob # unlimited retries, on non-zero exit
docker run --restart=on-failure:5 myjob # max 5 retriesUse for batch jobs that should retry on transient failure but eventually give up. The host-reboot does not bring them back (they are jobs, not services).
always — restart no matter what
docker run --restart=always mysvc
# Crash, clean exit, host reboot → daemon brings it back every time.
# Even after `docker stop`, the daemon restarts it.The naming is literal: ALWAYS. Including after you stop it manually — to actually stop, you have to docker rm it. Surprising; usually you want unless-stopped instead.
unless-stopped — the production default
docker run --restart=unless-stopped mysvc
# Crash → restart. Host reboot → restart. Manual `docker stop` → STAYS stopped.The right policy for 95% of long-running services. Daemon restarts on failure or reboot; it respects your intent when you stop manually.
How it interacts with the daemon
- On container exit: the daemon checks the policy and decides whether to restart.
- On daemon restart (
systemctl restart docker): containers withalwaysandunless-stopped(that were running before the daemon restart) come back.on-failuredoes NOT — it is per-exit only. - On host reboot: same as daemon restart.
- The daemon uses exponential backoff between retries: 100ms, 200ms, 400ms, ... up to a cap. Prevents hot-loop crash storms.
Compose syntax
services:
api:
image: myapp
restart: unless-stopped # most common
worker:
image: myworker
restart: on-failure # job-style
oneoff:
image: alpine
command: echo hi
restart: "no" # one-shotNote: "no" in YAML must be quoted, otherwise YAML parses it as boolean false.
Common mistakes
Forgetting to set a policy on a long-running service
# WRONG: defaults to "no"; container does not survive a host reboot
docker run -d --name api -p 80:80 myapp
# RIGHT
docker run -d --name api -p 80:80 --restart=unless-stopped myappThis is the most common operations mistake on single-host deploys. The container works, you go home, the host reboots overnight, the service is down and your phone lights up.
Using always and being surprised manual stop does not stick
$ docker run -d --name api --restart=always myapp
$ docker stop api
$ docker ps # api is backalways literally means always. Use unless-stopped if you want manual stop to be respected.
Crash-loop without exit-code filter
# Container exits with code 0 but you want restart only on failure
docker run --restart=always myjob
# Restarts forever, even on clean exits. Probably not what you want.
# Better:
docker run --restart=on-failure myjobForgetting that on-failure does not survive reboot
If the container is paused or running when you reboot, on-failure does not bring it back. Use unless-stopped if you need reboot survival.
Restart policy + healthcheck
Docker's restart policy reacts to process exit, not to healthcheck unhealthy. An unhealthy container that has not exited is not restarted by Docker. To act on healthcheck:
- Swarm replaces unhealthy tasks with new ones (configurable).
- Compose with the
condition: service_healthyonly gates startup, not runtime restart. - Plain Docker: an external watchdog (autoheal container, custom script) can
docker restartbased on health status.
# willfarrell/autoheal: monitors and auto-restarts unhealthy containers
docker run -d \
--name autoheal \
-v /var/run/docker.sock:/var/run/docker.sock \
-e AUTOHEAL_CONTAINER_LABEL=autoheal \
willfarrell/autoheal
docker run -d --label=autoheal=true --health-cmd="..." myappReal-world usage
- Production single-host services:
unless-stoppedeverywhere, almost without exception. - CI / build containers: no restart policy (default
no). They run, exit, and stay exited. - Background workers:
on-failure:Nso transient crashes retry but a permanently-broken job eventually gives up. - Critical infrastructure (the host itself depends on it): sometimes
alwaysis justified — e.g., a security agent that must be up no matter what.
Follow-up questions
Q: What is the difference between always and unless-stopped?
A: always restarts even after manual docker stop. unless-stopped does not. Both survive crashes and host reboots; the difference is whether your intent (docker stop) is respected.
Q: Does the restart policy apply if I docker rm the container?
A: No — once removed, there is no container to restart. Policies operate on existing containers.
Q: How can I see which policy a container has?
A: docker inspect <name> --format '{{.HostConfig.RestartPolicy.Name}}'. Returns always, unless-stopped, on-failure, or empty for no.
Q: Does --restart apply when the container is in a Swarm service?
A: No. Swarm services use restart_policy: in the deploy config (with condition: any|on-failure|none, delay, max_attempts). The --restart flag is for standalone containers.
Q: (Senior) When should you NOT use a restart policy at all?
A: When something else is responsible for the container's lifecycle. K8s pods are managed by the kubelet — Docker restart policy is irrelevant inside a K8s pod (and ignored). Same for systemd-managed containers via docker run --rm from a unit. The rule: one restart authority per container; pick the orchestration layer that should own it.
Examples
Production-style service with multiple resilience layers
$ docker run -d \
--name api \
--restart=unless-stopped \
-p 3000:3000 \
-v api_data:/data \
--health-cmd='curl -f http://localhost:3000/health || exit 1' \
--health-interval=30s \
--memory=512m \
myapp:1.0- Process crash → daemon restarts via policy.
- Host reboot → container comes back.
- Manual
docker stop→ stays stopped (you know what you did). - Healthcheck makes status visible to monitoring + reverse proxies.
Compose: different policies per service
services:
api:
image: myapp
restart: unless-stopped
worker:
image: myworker
restart: on-failure # batch retries
migrator:
image: mymigrator
restart: "no" # one-shot, do not restart
profiles: [migrate] # opt-in profileDifferent shapes of work, different policies. The migrator should run once and stay exited.
Capping retries to prevent infinite loops
$ docker run -d --name flaky --restart=on-failure:3 myjob
# After 3 non-zero exits, the daemon stops trying.
$ docker ps -a --filter name=flaky --format '{{.Status}}'
Exited (1) 5 seconds ago # final state, no more retrieson-failure:N is the safety net for jobs that might fail forever. Without the cap, the daemon retries indefinitely.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.
Comments
No comments yet