Docker has no idea whether your application is actually working — only whether its main process is still running. A crashed process, an infinite loop, or a hung connection pool all look identical to Docker without an explicit health check:
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
docker ps then reports healthy/unhealthy/starting instead of just Up, and orchestrators (Compose's service_healthy condition, Kubernetes readiness probes, load balancers) can use that status to decide whether to route traffic to a container or restart it — a container that's technically "running" but returning 500s to its health endpoint is exactly the case a process-status check alone would miss.
Restart policies control what happens when a container's process exits:
docker run --restart unless-stopped myapp
| Policy | Behavior |
|---|---|
no (default) | Never restart automatically |
on-failure[:max-retries] | Restart only on a non-zero exit code, optionally capped |
always | Always restart, including after a Docker daemon restart |
unless-stopped | Like always, but stays stopped if you explicitly stopped it before the daemon restarted |
unless-stopped is the usual production default for a long-running service — it survives crashes and host reboots, but respects a deliberate docker stop.