Zero-downtime deployment is not a single technique you switch on — it is a checklist of every point where an in-flight request can be dropped while an instance restarts, and closing each one. A request gets dropped when traffic keeps arriving at an instance after that instance has already started shutting down, or when the instance exits before it has finished the requests it already accepted. Getting this right is mostly about sequencing: stop new traffic, wait, finish existing work, then actually exit. Get the sequencing wrong and every deploy drops a handful of real requests, invisible in a dashboard showing overall uptime but very visible to the specific users who hit it.
What changed in 2026
- Container platforms tightened default grace periods. Kubernetes, ECS, and Cloud Run all now make the gap between "stop routing traffic here" and "kill the process" more configurable and better documented by default.
- HTTP/2 and gRPC connection draining got real tooling support, since long-lived multiplexed connections need explicit draining rather than simply waiting for a TCP connection to close.
- Readiness-gated rollouts became a default, not an opt-in — most orchestrators now wait for a new instance's readiness probe to pass before removing an old one, tightening the whole rollover.
- Serverless platforms exposed shutdown hooks more consistently, giving functions a documented, if short, window to finish work before a forced termination.
The sequence that actually prevents dropped requests
- Orchestrator marks the instance as not-ready and removes it from load balancer rotation, before sending any shutdown signal to the process itself.
- Load balancer stops sending new requests, but connections already established may still be sending traffic for a few seconds — this is the deregistration delay, and it must be longer than your slowest typical request.
- The process receives SIGTERM and immediately stops accepting new connections, while continuing to finish requests already in progress.
- In-flight requests complete within a grace period sized to the slowest realistic request the service handles, not the median.
- The process exits, or is forcibly killed (SIGKILL) if it exceeds the grace period — which should be rare, not routine, if the grace period is sized correctly.
Skipping step 1, or making it happen at the same time as step 3 instead of before it, is the most common root cause of dropped requests during otherwise unremarkable deploys.
Readiness vs liveness vs the deregistration delay
| Check |
Question it answers |
Failure response |
| Liveness probe |
Is the process alive and not deadlocked? |
Restart the container |
| Readiness probe |
Should this instance receive traffic right now? |
Remove from load balancer rotation, do not restart |
| Load balancer deregistration delay |
How long to keep draining connections after removal? |
Traffic stops after the delay elapses, not instantly |
Conflating liveness and readiness is a common source of dropped requests: an instance that is alive but temporarily overloaded should fail readiness and get skipped, not be killed and restarted, which only adds more load to the remaining instances.
Common mistakes
Killing the process the instant SIGTERM is received. Handle the signal, stop accepting new work, and let existing requests finish — the whole point of graceful shutdown is that "stop" and "stop immediately" are different operations.
Setting the load balancer deregistration delay shorter than your slowest request. A five-second delay looks fine in a dashboard until a report-generation endpoint that takes eight seconds gets cut mid-response on every single deploy.
Not closing keep-alive connections during drain. A client with a persistent HTTP connection can keep sending requests to an instance that thinks it has already stopped accepting new work, unless the server explicitly signals the connection should close after the current request.
Deploying schema-incompatible code alongside the deploy that requires it. Zero-downtime deployment assumes old and new code run simultaneously for a window; see database migration strategies for 2026 for keeping the database compatible with both during that window.
FAQ
How long should a graceful shutdown grace period be?
Long enough to cover your slowest realistic request with margin — often 30 to 60 seconds for typical web APIs, longer for services with long-running requests like report generation or file processing.
Does zero-downtime deployment require multiple instances?
Yes, effectively — you need at least one instance still serving traffic while another restarts. A single-instance deployment cannot be zero-downtime by definition, no matter how well the shutdown sequence is tuned.
Is this the same as a rolling deployment?
Rolling deployment is one strategy for achieving zero downtime, replacing instances gradually. Blue-green and canary strategies achieve the same request-level guarantee through different traffic-shifting mechanics; see progressive delivery explained for 2026 for how those compare.
What is connection draining, specifically?
It is the period during which an instance being removed from rotation is allowed to finish requests on connections it already holds, while receiving no new ones — distinct from the application-level graceful shutdown happening inside the process at the same time.
Where to go next
See progressive delivery explained for 2026 for controlling how much traffic reaches new code in the first place, database migration strategies for 2026 for keeping schema changes compatible during the deploy window, and how to deploy a Next.js app in 2026 for a platform-specific walkthrough.