Skip to content

DevOps & Cloud

Zero-Downtime Deployments: A CI/CD Playbook for Small Teams

You don't need a platform team to deploy safely multiple times a day. Here's a practical CI/CD setup that scales from one engineer to twenty.

JO

James Okafor

· 3 min read

“We’re too small for CI/CD” is a myth that costs teams far more time than
the pipeline itself would take to build. Here’s a playbook that works for
teams of one to twenty engineers.

Start with the non-negotiables

Before anything else, get these three things in place:

  1. Automated tests that run on every push. If you don’t trust your test suite, deployment automation just automates shipping bugs faster.
  2. A single source of truth for environment configuration. Secrets and environment variables should live in one managed place (your host’s secret manager, not scattered .env files copied between machines).
  3. A reproducible build. Whether that’s a Docker image or a compiled artifact, the thing you test should be the exact thing you deploy.

The pipeline shape

A solid default pipeline looks like this:

  1. On every pull request: install dependencies, run the linter, run the full test suite, and run a security scan (dependency vulnerabilities at minimum).
  2. On merge to main: build a container image, tag it with the commit SHA, and push it to a registry.
  3. Deploy: pull the new image on your servers (or trigger your platform’s deploy), run any pending database migrations, then swap traffic over.

Achieving zero downtime

The specific mechanism depends on your infrastructure, but the principle is
universal: never stop serving traffic from the old version until the new
version is confirmed healthy.

  • Rolling deploys: bring up new instances/containers, wait for health checks to pass, then remove old instances one at a time.
  • Blue-green deploys: run two full environments and switch a load balancer or DNS record between them, keeping the old one on standby for instant rollback.
  • Database migration safety: additive migrations (add a column, backfill, then use it) can be deployed alongside the app; destructive migrations (drop a column, rename something in use) should be split across two deploys so the old and new code can both run against the schema during the transition.

Monitoring the deploy itself

Automate a health check immediately after deploy — a simple HTTP check
against a /up endpoint isn’t enough on its own; pair it with a brief
window of error-rate monitoring so a bad deploy triggers an automatic
rollback rather than waiting for a human to notice.

The payoff

Once this is in place, deploying stops being a special event that requires
a maintenance window and becomes a boring, multiple-times-a-day occurrence
— which is exactly the point. Boring deploys are safe deploys.

Written by

JO

James Okafor

DevOps & Cloud Lead

James designs CI/CD pipelines and cloud infrastructure for startups and scale-ups, with a focus on reliability and deployment safety.

Related articles