Restart Policies in Docker: An In-Depth Look
A deep, beginner-friendly guide that goes beyond the basics — exploring exactly how Docker's automatic recovery mechanism thinks, where it interacts with other systems, and where it quietly runs into its own limits.
Imagine an automatic sprinkler system in a garden. A simple version just turns on at a set time each day. A genuinely well-designed one, though, understands more nuance: it knows not to water again if it just rained, it knows to stop trying if a pipe is clearly broken rather than flooding the garden forever, and it knows the difference between “the hose disconnected by accident” and “someone deliberately turned the system off for the season.” Docker’s restart policies, on the surface, look like that simple timer-based sprinkler — a basic rule for bringing a container back after it stops. But underneath, there’s considerably more nuance worth understanding: how retries actually behave over time, how policies interact with the rest of the system, and where this mechanism’s real boundaries lie. This guide goes past the fundamentals into exactly that depth.
1A Fast Recap of the Fundamentals
A brief refresher to establish shared footing before going deeper.
A restart policy is a rule, attached to a container when it’s created, telling Docker exactly what to do the moment that container stops — whether to leave it stopped, or to automatically start it again. Docker offers four options: never restarting automatically at all, restarting only after a genuine failure, restarting under essentially any circumstance, and restarting under any circumstance except when a human deliberately stopped it.
Never Restart
The container stays stopped after it exits, no matter why it stopped.
Restart Only on Error
Restarted only if the exit code indicates something went wrong, not if it exited cleanly.
Always Restart
Restarted regardless of the reason, even overriding a manual stop after a host reboot.
Restart Unless Manually Stopped
Restarted like “always,” except a deliberate manual stop is respected and remembered across a host reboot.
With that foundation in place, the rest of this guide focuses on the mechanics beneath these four simple labels — the timing, the internal state tracking, and the situations where restart policies alone genuinely aren’t enough.
2The Restart Policy Is Stored, Not Just Applied Once
An important nuance about where this rule actually lives and how long it persists.
A restart policy isn’t a one-time instruction that Docker glances at only the moment a container first starts. It’s stored as a permanent part of that specific container’s own configuration, checked fresh every single time that container stops, for as long as the container itself continues to exist. This means a container that has already restarted automatically ten times will still be evaluated against that exact same policy an eleventh time, and a twelfth, indefinitely, until either the container is removed or its policy is explicitly changed.
flowchart TD
A[Container Created With a Restart Policy] --> B[Policy Stored in Container's Own Configuration]
B --> C[Container Stops]
C --> D[Docker Reads the Stored Policy]
D --> E[Decision Made: Restart or Leave Stopped]
E --> F{Container Restarted?}
F -- Yes --> C
F -- No --> G[Container Remains Stopped Until Manual Action]
Think of it like a standing instruction left with a house sitter, not a one-time favor. “Every time the smoke alarm battery dies, replace it” is a rule that applies indefinitely, every single time that situation recurs — not just the first time it happens.
3The Restart Count and Why It Matters
A piece of internal state Docker keeps that has real practical significance.
For each container, Docker internally tracks how many times it has been automatically restarted due to its restart policy. This number isn’t just trivia — it’s directly used by the “on-failure” policy’s optional retry limit, and it’s also one of the single most valuable pieces of information a person can check when trying to understand whether a container is genuinely healthy or quietly struggling in a loop.
This restart count reflects restarts caused specifically by the restart policy itself — not every single time a container has ever been started throughout its entire history, including manual starts. Understanding exactly what this number does and doesn’t include avoids drawing the wrong conclusion from it.
4The Real Shape of the Backoff Delay
Going beneath the simple statement “there’s a delay between retries” to understand its actual behavior.
When a container using the “on-failure” or “always”-style policies keeps crashing repeatedly, Docker doesn’t retry at a fixed, constant interval. It begins with a very short delay after the first failure, and that delay grows progressively longer with each additional consecutive failure — a pattern generally referred to as exponential backoff. This means the very first retry after a crash happens almost immediately, while the tenth consecutive retry might be separated from the ninth by a delay of many seconds or more.
sequenceDiagram
participant D as Docker Engine
participant C as Crashing Container
D->>C: Attempt 1 (near-instant delay)
C-->>D: Fails
D->>C: Attempt 2 (short delay)
C-->>D: Fails
D->>C: Attempt 3 (longer delay)
C-->>D: Fails
D->>C: Attempt 4 (even longer delay)
Note over D: Delay keeps growing with each consecutive failure
It’s similar to how a person might handle a car that won’t start: try again immediately once, then wait a minute and try again, then wait several minutes before the next attempt, rather than turning the key over and over again with no pause at all, which would likely just drain the battery faster.
This growing delay directly protects the host system from being overwhelmed by an extremely rapid, tight restart loop, and it also gives any temporary underlying issue — a dependency that’s briefly unavailable, for instance — meaningfully more time to resolve itself between attempts as the failures continue.
5What Counts as “Failure” Beyond a Simple Crash
Broadening the definition of failure beyond the obvious case.
It’s easy to think of “failure” purely in terms of an application crashing with an obvious error. But the exit-code mechanism that “on-failure” relies on is more general than that — it captures any situation where the container’s main process exits with a non-zero code, which can include far subtler situations: a process that couldn’t find a required configuration value and deliberately exits rather than running incorrectly, or a startup routine that intentionally fails fast because a dependency it needs isn’t ready yet.
Unhandled Crash
The application encounters an unexpected error it has no way to gracefully handle, and the process terminates abnormally.
Intentional Early Exit
The application detects a problem — like missing required configuration — and deliberately exits with a non-zero code rather than continuing in a broken state.
Startup-Time Dependency Check
The application checks for a required dependency, like a database, at startup, and exits if that dependency isn’t yet reachable, expecting the restart policy to naturally retry once conditions improve.
That last case — an application deliberately exiting when a dependency isn’t ready — is actually a legitimate, common design pattern. It effectively delegates the “keep trying until the dependency becomes available” logic to the restart policy itself, rather than building that retry logic separately inside the application.
6Restart Policies and Health Checks: A Deeper Relationship
Exploring how restart policies interact with a completely separate, but related, mechanism.
Docker supports a separate concept called a health check — a way for a container to periodically report whether it’s not just running, but genuinely healthy and functioning correctly, independent of whether its main process has actually exited. A container can be technically “running” from the restart policy’s point of view, while simultaneously being reported as “unhealthy” by its health check — these are two distinct, related-but-separate signals.
flowchart TD
A[Container's Main Process] --> B{Is the process still running?}
B -- No --> C[Restart Policy Decides What Happens Next]
B -- Yes --> D{Does the Health Check Pass?}
D -- Yes --> E[Reported as Healthy]
D -- No --> F[Reported as Unhealthy, But Still Running]
A restart policy alone does not automatically restart a container purely because its health check is failing. If an application’s process is technically still alive but stuck, deadlocked, or otherwise unable to serve requests, the restart policy has nothing to react to on its own, since nothing has actually stopped.
To bridge this gap, many real systems configure the application itself to exit deliberately when it detects it’s in a genuinely unhealthy, unrecoverable state — turning an “unhealthy but technically alive” situation into an actual process exit, which the restart policy can then properly react to.
7The Retry Limit: A Feature Specific to “On-Failure”
Understanding a capability that only exists for one specific policy, and why that design makes sense.
Only the “on-failure” restart policy supports an explicitly configurable maximum retry count — a hard ceiling on how many times Docker will attempt to restart before giving up entirely and leaving the container stopped. Neither “always” nor “unless-stopped” offer this same built-in cap; both are designed around the philosophy that a container meant to run indefinitely should keep being retried indefinitely, since giving up entirely would mean a service meant to be permanently available becomes permanently unavailable instead.
| Policy | Supports a Retry Limit | Underlying Philosophy |
|---|---|---|
| On-Failure | Yes, optional and configurable | A task expected to eventually succeed or genuinely give up |
| Always | No | A permanent service that should never simply give up |
| Unless-Stopped | No | Same as “always,” but respecting an explicit manual stop |
A retry limit makes sense for a delivery driver trying to reach someone by phone a reasonable number of times before giving up and trying a different approach. It makes far less sense for a hospital’s emergency generator, which should keep trying to restart indefinitely after a failure, since giving up isn’t an acceptable outcome for something that critical.
8What Happens When the Retry Limit Is Reached
A specific, important edge case worth understanding clearly.
Once a container configured with “on-failure” and a maximum retry count has exhausted that limit without a single successful, sustained run, Docker stops attempting to restart it and leaves it in a stopped state. Crucially, this doesn’t remove the container, and it doesn’t change its stored restart policy — it simply means Docker has, for now, given up on automatic recovery, and the container will sit stopped until a person intervenes.
A container that has hit its retry limit is a strong, unambiguous signal that something is genuinely broken and needs direct human attention — it’s meaningfully different from a container that’s merely restarted once or twice and then stabilized successfully.
9Restart Policies Across a Host Reboot
A deeper look at exactly how these policies behave when the entire underlying machine restarts.
When the host machine itself reboots, the Docker Engine, once it comes back up, reviews every container it’s still tracking and checks each one’s restart policy to decide whether it should be automatically started again as part of that boot process. This is what allows “always” and “unless-stopped” containers to come back to life without any human action, even after the entire machine has been powered off and back on.
flowchart TD
A[Host Machine Reboots] --> B[Docker Engine Starts Back Up]
B --> C[Engine Reviews Every Tracked Container]
C --> D{What was the container's restart policy?}
D -- No or On-Failure with clean history --> E[Leave Stopped]
D -- Always --> F[Start Automatically]
D -- Unless-Stopped, wasn't manually stopped --> F
D -- Unless-Stopped, was manually stopped --> E
This is precisely why “always” and “unless-stopped” are the policies of choice for genuinely critical, long-running services — a planned maintenance reboot of the host machine doesn’t require anyone to remember to manually restart every important container afterward.
10Restart Policies vs Orchestration-Level Recovery
Understanding where this single-host mechanism fits relative to larger, multi-host systems.
Restart policies operate entirely within the scope of a single Docker Engine on a single host machine. Larger orchestration systems, designed to manage containers across many machines working together, typically implement their own, more sophisticated recovery logic — one that can, for example, decide to relaunch a failed container on a completely different, healthy machine, rather than being limited to simply retrying it on the same host where it originally failed.
| Aspect | Docker Restart Policy | Orchestration-Level Recovery |
|---|---|---|
| Scope | A single host machine | Potentially many machines working together |
| Can relocate a failed workload elsewhere | No | Often, yes |
| Awareness of overall cluster health | None | Typically built in |
| Complexity to set up | Minimal, built directly into every container | Requires a separate, more complex system |
A restart policy is like a single employee who, if they trip and fall, gets back up and keeps working at their same desk. Orchestration-level recovery is more like a manager who notices an entire desk has become unusable and reassigns that person’s work to a different desk entirely, somewhere else in the building.
11The Limits of What a Restart Policy Actually Solves
Being honest and precise about where this mechanism’s usefulness genuinely ends.
Symptom, Not Cause, Recovery
A restart policy reacts to a process stopping — it has no understanding of, and no ability to fix, whatever underlying bug or misconfiguration actually caused that stop in the first place.
A Frozen but Still-Running Process
A process that’s technically still running, but stuck and unresponsive, gives the restart policy nothing to react to, since nothing has actually stopped from its point of view.
Bound to a Single Host
If the entire host machine itself is genuinely unavailable — not just rebooting, but truly down — a restart policy alone offers no path to running that workload somewhere else instead.
Silent by Default
Automatic restarts happen quietly, on their own, with no built-in notification to a human unless a separate monitoring system is specifically watching for repeated restarts.
12Advantages, Disadvantages, and Trade-offs
Weighing the deeper, nuanced value of restart policies against their genuine, specific limits.
Advantages
- Provides automatic, immediate recovery from crashes with essentially zero configuration overhead
- The growing backoff delay protects the host from being overwhelmed by a tight, rapid crash loop
- Works consistently across host reboots, keeping critical services available without manual intervention
- Composes naturally with an application’s own deliberate-exit-on-dependency-failure pattern
- Requires no separate infrastructure — the mechanism lives entirely within the Docker Engine itself
Disadvantages / Trade-offs
- Has no awareness of a container that’s technically running but genuinely unhealthy, unless the application itself is designed to exit in that case
- Is entirely bound to a single host, offering no way to relocate a workload if the host itself becomes unavailable
- Provides no built-in alerting, meaning a repeatedly crashing container can go unnoticed without separate monitoring
- Cannot diagnose or fix whatever underlying issue is actually causing the failures in the first place
13Best Practices and Common Mistakes
More advanced habits, going beyond the basics, for teams relying on restart policies in real systems.
For applications where “technically running but unhealthy” is a real risk, design the application to detect that state itself and deliberately exit, effectively converting a gap that restart policies can’t see into a signal they can directly react to.
Treating a low restart count as automatic proof that everything is fine, without considering that a container could be quietly unhealthy in ways the restart policy has no visibility into at all.
Relying purely on a restart policy for a genuinely multi-host, high-availability system, when orchestration-level recovery is actually needed to handle the case of an entire host becoming unavailable.
Pair restart policies with active alerting on restart counts, so repeated automatic recoveries — which are silent by default — actually reach a human’s attention rather than being invisibly absorbed by the system indefinitely.
14Design Patterns and Anti-Patterns
More advanced patterns for structuring how a system relies on automatic restart behavior.
Problem
Building an application that can become stuck in an unresponsive, hung state without ever actually exiting, while relying entirely on a restart policy to eventually recover it.
Why It’s Harmful
Since nothing has actually stopped from the restart policy’s perspective, it has no trigger to act on at all — the application can remain stuck indefinitely, technically “running” but completely unable to serve its purpose, with no automatic recovery ever kicking in.
Correct Approach
Combine a restart policy with a health check and application-level logic that deliberately exits once a genuinely unrecoverable, unhealthy state is detected, giving the restart policy an actual event to react to.
Problem
An application needs to wait for a dependency, like a database, to become available at startup, without writing custom retry logic inside the application itself.
Why It’s Harmful
N/A — this describes the recommended solution rather than a problem to avoid.
Correct Approach
Have the application check for the dependency once at startup and exit immediately with a failure code if it isn’t ready, relying on an “on-failure” restart policy — with a reasonable retry limit — to naturally retry the entire startup sequence with the built-in growing delay, until the dependency finally becomes available.
15Monitoring and Deeper Observability
Going beyond a simple glance at whether a container is currently running.
Genuinely useful monitoring around restart policies looks past the simple “is it running right now” question, and instead tracks the restart count over time, the pattern of how frequently restarts are happening, and — where health checks are configured — how the health status correlates with those restarts. A container that restarted once, weeks ago, and has been stable ever since tells a very different story than one that has restarted five times in the last hour, even though both might currently show as “running.”
Treating a rising restart count as a genuine alerting signal, not just a passive data point, closes much of the visibility gap that restart policies leave open on their own — turning silent, automatic recoveries into something a team actually notices and can act on.
16Security Considerations
A closer, more nuanced look at the security implications of automatic restart behavior.
Repeated Crashes From an Attack
If a vulnerability causes a crash when triggered, aggressive automatic restarting can keep the service available across repeated exploitation attempts, potentially without anyone noticing the pattern unless restart activity is actively monitored.
A Restart Loop as an Indirect Denial-of-Service Risk
A container stuck in a rapid restart loop consumes real CPU and I/O on the host repeatedly, and at scale, this can meaningfully degrade the performance of other, unrelated containers sharing that same machine.
Mistaking “Running” for “Secure”
A service that keeps coming back up after every crash can create a false sense that everything is fine, when in reality it may be repeatedly failing due to a genuine, unaddressed security issue that deserves direct investigation.
17Real-World and Industry Examples
How these deeper mechanics show up in real, production-grade systems.
Startup-Order Dependency Handling
Teams running a database alongside an application that depends on it commonly rely on the application’s deliberate-exit-on-missing-dependency pattern, combined with an “on-failure” policy, to naturally handle startup ordering without complex, custom coordination logic.
Small Self-Managed Production Systems
Teams without a full orchestration platform frequently lean heavily on “unless-stopped” combined with active restart-count monitoring, treating this combination as their primary, practical line of defense against unattended downtime.
Systems Layered Beneath Orchestration
Even within larger orchestrated environments, individual container-level restart behavior often still plays a supporting role beneath the orchestration system’s own, broader recovery logic, handling the fast, local case while orchestration handles the larger, cluster-wide case.
Long-Running Background Workers With Health Checks
Worker processes that can silently get stuck without crashing outright are often built to actively self-check their own health and deliberately exit if something is clearly wrong, specifically to give their restart policy something concrete to act on.
18Frequently Asked Questions
Generally, once a container has run successfully and stayed up for a meaningful, sustained period, a subsequent failure is treated as a fresh occurrence, and the delay pattern effectively starts over from its short, initial value again.
No — a restart policy only reacts to the main process actually exiting. A stuck but still-running process requires a separate mechanism, like a health check combined with application-level logic, to actually convert that stuck state into a process exit the restart policy can respond to.
The restart count specifically reflects automatic restarts triggered by the policy itself; a manual restart initiated directly by a person is a separate action, and its effect on that stored count can depend on the specific circumstances of how and why the container had stopped beforehand.
Changing the policy affects how future stops are handled going forward — it doesn’t retroactively alter what has already happened in the past under the previous policy.
On their own, no — they provide solid, automatic recovery within a single host, but true high availability, especially the ability to survive an entire host becoming unavailable, generally requires an orchestration-level system layered on top.
Only in the limited sense of the exit code — whether it indicated success or failure. It has no deeper insight into the actual underlying cause, and it makes no attempt to diagnose or address that cause itself.
19Summary and Key Takeaways
Beneath their simple, four-option surface, Docker’s restart policies carry real, worthwhile depth: a stored, permanently re-evaluated rule, a tracked restart count, a deliberately growing backoff delay designed to protect the host, and a meaningful, specific boundary around what they can and cannot actually detect or fix. Understanding that restart policies react only to a process genuinely exiting — not to a process that’s merely unhealthy or stuck — reveals exactly why they pair so well with health checks and deliberate, application-level exit behavior. And recognizing that they operate entirely within a single host explains precisely why larger, multi-host systems need a more sophisticated, orchestration-level layer of recovery on top. Used with this deeper understanding, restart policies become a precise, well-calibrated tool rather than a vague, general-purpose safety net.
Key Takeaways
- The policy is stored permanently on the container — re-evaluated every single time it stops, not just once at the beginning.
- Backoff delay grows with each consecutive failure — protecting the host from a tight, rapid crash loop rather than retrying at a fixed pace.
- Only “on-failure” supports a retry limit — reflecting a deliberate design distinction between tasks meant to eventually give up and services meant to run forever.
- Restart policies can’t see a “stuck but running” process — that gap is closed by combining them with health checks and deliberate application-level exits.
- They’re bound to a single host — larger, multi-host recovery genuinely requires an orchestration-level system layered on top.
- Restart activity is silent by default — active monitoring of restart counts is what turns automatic recovery into something a team actually notices.
- They fix the symptom, never the cause — a repeatedly restarting container is a strong, clear signal that deserves direct human investigation, not just quiet tolerance.