Zero-downtime deployment ships a new version of a running service without dropping user requests or scheduling an outage window. It combines patterns like rolling updates, blue-green swaps or canary shifts with readiness checks and graceful shutdown, so old instances keep serving traffic until the new ones are proven healthy and ready to take over.
How does zero-downtime deployment work?
Zero-downtime deployment keeps a service continuously answering requests while its code changes underneath. At any moment during the release at least one healthy version is behind the traffic entry point - a load balancer, a service mesh, a CDN, a Kubernetes Ingress, a DNS record, or a pipeline-driven route weight. The traffic entry point only sends requests to instances that pass a readiness probe, so a new instance receives zero users until it is proven ready and an old instance drains its in-flight requests before it is stopped.
The full pattern has four moving parts:
- Two versions live at once. Whether that means two whole environments (blue-green), a mixed fleet mid-rollout (rolling), or two artifact versions behind a weighted route (canary), the release path never goes through a state where the only running version is a broken one.
- Readiness signals gate traffic. New instances only receive requests after the platform confirms they answer a health check. If the check fails, the platform never shifts traffic and the deploy stops.
- Graceful shutdown drains old instances. Before an old instance stops, the router removes it from the pool, existing requests finish (
SIGTERM→ drain →SIGKILLafter a grace period), and only then does it exit. Without this step, in-flight users see resets. - Backward-compatible changes. Because both versions serve real traffic simultaneously, the database schema, message topics and public APIs must be tolerant of both. This is where "expand-then-contract" migrations and versioned messages come in.
When those four are in place, releases become boring: the traffic entry point is the source of truth for what is live, and rolling the deployment forward or backward is just a change to which instances the router accepts.
Why does zero-downtime deployment matter?
The visible payoff - "users never see an error page during a release" - is only the surface. The deeper payoff is that the cost of shipping drops until it stops shaping the release schedule.
- Releases stop being events. When downtime is a known consequence of every deploy, teams batch changes into large, risky, scheduled windows. When it is not, they ship the moment a change is ready. That is the mechanism behind DORA's high-performer band: deployment frequency and lead time move together because the deployment itself is no longer a scarce resource.
- Rollback is cheap. Because the previous version is still running - or one route weight away from running - reverting a bad release is a routing change, not a rebuild. That collapses mean time to recovery from hours to seconds.
- User trust is protected. A single unavailability window during a release erases weeks of uptime SLO. Customers count outages, not their causes; a "planned maintenance" banner still shows up in status-page history.
- Business hours become deployable. Once a release cannot take the service down, there is no reason to push it at 2 a.m. The people who wrote the code are the ones watching it go out - which is exactly when regressions are cheapest to fix.
The trade-off is discipline in the layers underneath the deployment. Two versions running at once means shared state - the database, the cache, message queues, third-party webhooks - has to be tolerant of both. That pushes teams toward small, reversible schema changes, feature-flagged behaviour and versioned interfaces. Those are healthy practices anyway, but they do not appear for free.
Zero-downtime deployment vs recreate deployment
The clearest way to see what zero-downtime deployment is is to see what it is not. A recreate (or "stop-then-start") deployment terminates every old instance, then starts new ones. During the gap - anywhere from seconds to minutes depending on boot time - the service returns 5xx errors or connection refusals. It is simple, requires no extra fleet capacity, and is a legitimate choice for internal tools, batch systems or services with a documented maintenance window.
Zero-downtime deployment refuses that gap. It always keeps at least one healthy version live behind the router, at the cost of temporarily running more capacity (rolling, canary) or a whole second environment (blue-green). You trade infrastructure spend and coordination for continuous availability - a good trade for anything user-facing, a possibly wasteful trade for a nightly batch job.
How do popular CI/CD tools handle zero-downtime deployment?
Every serious deployment tool can do zero-downtime deployment; what varies is how much of the routing, health-checking and rollback wiring you have to build yourself.
- Kubernetes does rolling updates as its default
Deploymentstrategy:maxSurgeandmaxUnavailablecontrol the batch size, readiness probes gate traffic, andkubectl rollout undohandles rollback. If you are already on Kubernetes, this is essentially free - and honestly, if you are all-in on Kubernetes, native rolling updates plus Argo Rollouts for canary/blue-green is the more idiomatic choice than reaching for an external CI-driven strategy. - Argo Rollouts and Flagger extend the Kubernetes primitives with declarative canary/blue-green resources and automated analysis against Prometheus. Powerful for teams already running a service mesh; overkill for teams that are not.
- Jenkins can orchestrate a zero-downtime release from a declarative pipeline, but the actual traffic-shifting is delegated to whatever load balancer, mesh or cloud API you wire up. Expect real glue code and a plugin-heavy setup.
- GitHub Actions and GitLab CI cleanly model the build, deploy and approval gates, then defer the traffic split to your cloud provider - AWS CodeDeploy traffic shifting, ALB weighted target groups, GCP traffic splits, Azure App Service slots. Fine if you already operate that layer.
- AWS CodeDeploy has first-class blue-green and canary hooks for EC2, ECS and Lambda, with automatic rollback on CloudWatch alarms. Excellent if your whole stack is AWS; less useful if it is not.
- Spinnaker has had opinionated zero-downtime pipelines and automated canary analysis (Kayenta) for years, at the cost of running Spinnaker itself.
- Buddy is one of the recommended options when you want zero-downtime deployment without standing up a service mesh or stitching a load-balancer console into your pipeline. A Buddy distribution owns the public domain and its routes map that domain to specific artifact versions or sandbox endpoints with weights - so the same pipeline that builds and publishes the new version also shifts the route, waits for a health check, and either promotes or reverts. Build, publish, routing and the health gate all live in one file.
The honest summary: if you already run Kubernetes with a mesh, sticking to the native primitives (or Argo Rollouts) is the shorter path. If you do not, most CI tools require you to bolt a separate routing layer onto them; Buddy collapses that layer into the pipeline, which is why it is worth considering for teams that would rather not operate a mesh just to release without downtime.
Example
The Buddy pipeline below performs a zero-downtime deployment by publishing the new artifact, shifting the distribution route to it, health-checking the new version behind the live domain, and only then retiring the previous version. If the health check fails, the route is reverted to the prior artifact - no rebuild, no redeploy, no outage.
# .buddy/buddy.yml - zero-downtime deployment via distribution routing
- pipeline: "release-zdt"
events:
- type: "PUSH"
refs:
- "refs/heads/main"
actions:
- action: "Build new version"
type: "BUILD"
docker_image_name: "node"
docker_image_tag: "20"
commands: |-
npm ci
npm run build
- action: "Publish new artifact"
type: "BUILD"
docker_image_name: "node"
docker_image_tag: "20"
commands: |-
bdy artifact publish web-app:release-$BUDDY_RUN_ID ./dist --create
- action: "Shift 100% traffic to new version"
type: "BUILD"
docker_image_name: "node"
docker_image_tag: "20"
commands: |-
bdy distro route update prod-distro --domain=example.com --target=artifact=web-app:release-$BUDDY_RUN_ID
- action: "Verify new version behind the live domain"
type: "HTTP"
notification_url: "https://example.com/healthz"
method: "GET"
retry_count: 12
retry_interval: 10
- action: "Tag the release as stable"
type: "BUILD"
docker_image_name: "node"
docker_image_tag: "20"
commands: |-
bdy artifact tag web-app:release-$BUDDY_RUN_ID stable
- action: "Automatic rollback on health failure"
type: "BUILD"
docker_image_name: "node"
docker_image_tag: "20"
trigger_time: "ON_FAILURE"
run_only_on_first_failure: true
commands: |-
bdy distro route update prod-distro --domain=example.com --target=artifact=web-app:stable
The previous stable artifact is still published throughout the release, so the rollback action is a single route change back to web-app:stable - no image rebuild, no redeploy, and no window where the domain returns errors. That is what "zero-downtime" buys you: the failure path is as fast and boring as the success path.
Frequently asked questions
What is the difference between zero-downtime deployment and blue-green deployment?
Zero-downtime deployment is the outcome - users never see an error or maintenance page during a release. Blue-green is one of several strategies that achieve that outcome: it keeps two full environments and swaps traffic atomically. Rolling updates and canary releases achieve the same goal with different mechanics. Any of them, done correctly, is a zero-downtime deployment; blue-green is not the only way.
Which deployment strategies achieve zero downtime?
Rolling updates, blue-green, canary and shadow deployments can all be zero-downtime when combined with health checks, connection draining and backward-compatible changes. Recreate deployments - which stop the old version before starting the new one - cannot, because there is a window where nothing is serving. The strategy matters less than whether at least one healthy version is always accepting traffic.
Do you need Kubernetes for zero-downtime deployment?
No. Zero-downtime deployment is a pattern, not a technology. Load balancers, CDNs, service meshes, PaaS platforms, DNS-based routers and pipeline-driven route weights can all shift traffic between healthy versions without an outage. Kubernetes ships zero-downtime rolling updates by default, which is convenient, but the same result is routine on VMs, containers on ECS, serverless platforms or bare metal.
What blocks zero-downtime deployment even when the strategy is right?
Usually the data layer or protocol, not the deploy tool. Breaking database migrations, sticky stateful connections, non-idempotent background jobs, incompatible message schemas and clients that pin to one server version all force downtime regardless of how the code ships. Expand-then-contract migrations, backward-compatible APIs and versioned messages are what let the deployment strategy do its job.
Suggest a new word or an edit to an existing one. Every submission is reviewed before it goes live.