Skip to main content

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> on docker run (or restart: <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-failure adds.

The four policies

PolicyOn exit (any code)On exit code 0After host rebootRespects manual stop
no (default)nononon/a
on-failure[:N]yes if code != 0, up to N timesnono (does not survive reboot)yes
alwaysyesyesyesno (restarts even after stop)
unless-stoppedyesyesyes (if was running)yes

no — the default

bash
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

bash
docker run --restart=on-failure myjob # unlimited retries, on non-zero exit docker run --restart=on-failure:5 myjob # max 5 retries

Use 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

bash
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

bash
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 with always and unless-stopped (that were running before the daemon restart) come back. on-failure does 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

yaml
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-shot

Note: "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

bash
# 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 myapp

This 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

bash
$ docker run -d --name api --restart=always myapp $ docker stop api $ docker ps # api is back

always literally means always. Use unless-stopped if you want manual stop to be respected.

Crash-loop without exit-code filter

bash
# 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 myjob

Forgetting 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_healthy only gates startup, not runtime restart.
  • Plain Docker: an external watchdog (autoheal container, custom script) can docker restart based on health status.
bash
# 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="..." myapp

Real-world usage

  • Production single-host services: unless-stopped everywhere, almost without exception.
  • CI / build containers: no restart policy (default no). They run, exit, and stay exited.
  • Background workers: on-failure:N so transient crashes retry but a permanently-broken job eventually gives up.
  • Critical infrastructure (the host itself depends on it): sometimes always is 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

bash
$ 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

yaml
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 profile

Different shapes of work, different policies. The migrator should run once and stay exited.

Capping retries to prevent infinite loops

bash
$ 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 retries

on-failure:N is the safety net for jobs that might fail forever. Without the cap, the daemon retries indefinitely.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Comments

No comments yet