How to Match Docker Restart Policies to Databases, Workers, and Web Apps

Eva Wong is the Technical Writer and resident tinkerer at ZimaSpace. A lifelong geek with a passion for homelabs and open-source software, she specializes in translating complex technical concepts into accessible, hands-on guides. Eva believes that self-hosting should be fun, not intimidating. Through her tutorials, she empowers the community to demystify hardware setups, from building their first NAS to mastering Docker containers.

Match Docker restart policies to service lifecycle and exit semantics rather than assigning unless-stopped to every container in a Compose file.

Restart policies react when a container's main process exits; a health check can mark a still-running process unhealthy without automatically restarting it. Databases, workers, web apps, migrations, and scheduled jobs therefore need different choices based on whether they are meant to stay alive, what a clean exit means, and how repeated failure should be surfaced.

Separate Restart Behavior From Health and Readiness

A restart policy answers whether Docker should start a container again after its process stops. A health check answers whether the running service can perform a defined operation. Dependency readiness answers whether another service should begin yet. They solve related but different problems.

A 2026 health and restart are separate explains this separation and shows how Compose health conditions can delay dependent startup until a service is actually ready.

Do not expect restart: always to repair an unhealthy web process that never exits, and do not expect a health check alone to restart it. Make the application exit when continuing is unsafe, add an external remediation mechanism, or alert on unhealthy state according to the service design.

Use Persistent Restart Policies for Long-Lived Databases

A home-server database is normally expected to return after a host or Docker daemon restart. unless-stopped is often a practical default when an intentional administrator stop should remain respected; always is appropriate when reboot should override that manual-stop state by design.

A July 2026 restart policy follows process exit details the difference among no, on-failure, always, and unless-stopped, including the fact that policy reacts to process exit rather than health status.

The database also needs a real health check and durable storage. Restarting PostgreSQL repeatedly cannot fix a full disk, invalid configuration, corrupt state, or an incompatible migration. Alert on repeated restarts instead of treating them as successful resilience.

Choose Worker Policy From Queue and Exit Semantics

A long-running queue worker may deserve unless-stopped if it should always be consuming work. A finite worker or batch process may use on-failure:N so transient errors receive bounded retries while a persistent failure stops visibly.

A current bounded on-failure retries emphasizes that retry behavior should match whether a process is supposed to be permanently alive or allowed to finish normally.

Know what exit code 0 means for the worker image. If it means โ€œjob complete,โ€ always can turn a successful one-shot job into an endless loop. If the worker is meant to be a daemon, a clean unexpected exit may still justify an automatic return through unless-stopped.

-15% OFF
Single board computer zimaboard2

Keep Web Apps Long-Lived but Gate Them on Real Dependencies

Most self-hosted web applications are intended to remain available continuously, so unless-stopped is usually easier to reason about than a bounded failure-only policy. The restart setting does not remove the need for the database, cache, DNS, secrets, and mounted paths to be ready.

The related ZimaSpace diagnostic on container dependency restart loops shows why repeatedly restarting the visible app can obscure the database, cache, mount, migration, or memory failure that happened first.

Use dependency health checks for startup ordering where appropriate and make application retry behavior bounded. A web service that crashes every five seconds until PostgreSQL starts is less observable than one that waits for readiness and produces one clean startup.

Give Migrations and One-Shot Jobs a Finite Lifecycle

Migration containers, importers, maintenance tasks, and one-time initialization jobs are not ordinary daemons. Their success state is often โ€œexit 0 and remain stopped.โ€ Using always or unless-stopped can rerun completed work unintentionally.

Keep one-shot operational tools explicit instead of allowing them to become hidden always-on services. A migration or importer should have a finite success state that remains visible after the command exits.

Use restart: "no" when failure should stop for inspection, or bounded on-failure only when the command is safe to retry. For schema migrations, prove that repeating a partially applied migration is supported before automating retries.

Test the Policy With Real Failure Modes

For each service, test a clean process exit, non-zero crash, host reboot, Docker daemon restart, manual stop, unhealthy-but-running condition, and unavailable dependency. Record the expected state after each event before calling the configuration resilient.

Track restart count and alert when it crosses a small threshold in a time window. Automatic restart should reduce recovery time from transient failure; it should not make a persistent crash invisible by producing an endless stream of new containers.

A good policy matrix is explicit: long-lived databases and web apps return after infrastructure restarts, daemon workers recover according to queue semantics, finite jobs stop when complete, and health/readiness checks expose failures that restart policy cannot see.

Support & Tips

More to Read

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.