Zero-downtime deploys, explained

'Zero-downtime deploy' gets thrown around a lot. Here's what it actually means, the mechanics that make it work, and why a good platform guarantees a broken build can never take production offline.

June 26, 2026·5 min read

A zero-downtime deploy means shipping a new version of your app without any request ever hitting a closed door. No maintenance page, no dropped connections, no window where the site is down while the new code starts up. Done right, users never notice a deploy happened at all.

The naive deploy, and why it hurts

The simplest deploy stops the running app, swaps in new code, and starts it again. The problem is the gap: between 'stopped' and 'started and ready', every request fails. On a slow-booting app that can be several seconds of errors on every single deploy — and if the new version crashes on startup, the downtime is indefinite.

The fix: start new, then switch

Zero-downtime deploys invert the order. Instead of stopping the old version first, you start the new one alongside it and only cut traffic over once it's proven healthy:

  1. 1Start the new version as a fresh container, while the old one keeps serving every request.
  2. 2Health-check it — the platform polls a health endpoint (or the app's port) until the new version reports ready.
  3. 3Switch traffic at the reverse proxy the instant it's healthy — new requests go to the new version.
  4. 4Retire the old version once it has drained its in-flight requests.

At no point is there a gap with nothing serving. This pattern — sometimes called a rolling release, and closely related to blue-green deployment — is the foundation of every credible modern deploy system.

The health check is the safety net

The health check is what makes it safe, not just seamless. Because traffic only switches after the new version passes, a build that crashes on startup or fails its check never receives a single request — the old version simply keeps serving. A bad deploy becomes a non-event instead of an outage.

The rule to internalise: a failed deploy should leave production exactly as it was. If a broken build can take your site down, you don't have zero-downtime deploys — you have fast deploys with a blast radius.

Where migrations fit

Database migrations are the classic thing that breaks zero-downtime deploys, because the old and new code briefly run against the same database. Two habits keep it clean:

  • Run migrations in a release step that executes once, before traffic switches — not inside every web process on boot.
  • Make migrations backward-compatible so the old version can tolerate the new schema during the brief overlap: add columns before you use them, and remove them a deploy later.

Do you have to build this yourself?

No — and you shouldn't. Orchestrating start-check-switch-drain by hand is fiddly and easy to get subtly wrong. A single-server PaaS like DeployCloud does health-checked rolling releases automatically on every git push: the new release only goes live after it passes its check, and because the previous image is kept, rolling back is one click. You get the guarantee without writing the orchestration.

Frequently asked questions

What is a zero-downtime deploy?

A deployment that ships a new version without any request failing. The new version starts and is health-checked alongside the old one, and traffic only switches once it's proven healthy — so users never hit downtime, even mid-deploy.

What's the difference between rolling and blue-green deployment?

Both start the new version before retiring the old to avoid a gap. Blue-green keeps two full environments and flips between them; a rolling release replaces instances incrementally. In practice a single-server PaaS gives you the same zero-downtime guarantee via a health-checked switch.

What happens if the new version fails its health check?

Traffic never switches. The old version keeps serving every request and the deploy is marked failed. That's the whole point — a broken build should be a non-event, not an outage.

How do database migrations work with zero-downtime deploys?

Run them in a release step that executes once before traffic switches, and keep them backward-compatible so the old code tolerates the new schema during the brief overlap. Add columns before using them; drop them a deploy later.

Deploy your first app today.

Self-hosted, open, and yours. Point it at a repo and go — no credit card, no lock-in.