Skip to content
DevOps

Blue-Green vs Canary Deployments: Which Should You Use?

Both deploy without downtime. Both have trade-offs. Picking the wrong one for your situation is worse than picking none at all. Here's how to choose.

February 11, 2025 7 min readBy ShipReady

You want to ship without downtime. Two deployment strategies dominate the conversation: blue-green and canary. Both work, both have trade-offs, and picking the wrong one for your situation is worse than picking none at all.

Here's how to actually choose.

Blue-green deployments

How it works: You run two identical production environments — "blue" (live) and "green" (idle). You deploy the new version to green, run smoke tests, then flip the router to send all traffic to green. Blue becomes the new idle environment, ready for rollback.

Before deploy:  Traffic → [Blue v1.2]   [Green idle]
After deploy:   Traffic → [Blue idle]   [Green v1.3]
Rollback:       Traffic → [Blue v1.2]   [Green v1.3]  (instant)

Pros:

  • Instant rollback. Flip the router back to blue. No redeploy, no waiting.
  • Zero downtime. The switch is atomic.
  • Full-production testing. Green runs the real config, real traffic shape (if you shadow traffic), real everything before it's live.

Cons:

  • 2x infrastructure cost. You're paying for two full environments, always.
  • Database migrations are hard. If v1.3 changes the schema, blue and green can't both serve traffic against the same DB. You need backward-compatible migrations or a dual-deploy dance.
  • Stateful services don't play nice. Anything with in-memory sessions, WebSocket connections, or sticky sessions needs careful handling at the switch.

When to use blue-green:

  • You have the budget for 2x infra.
  • Your app is mostly stateless.
  • Your database migrations are backward-compatible (or you can tolerate brief dual-running).
  • You value instant rollback above all else.

Canary deployments

How it works: You deploy the new version alongside the old one, then route a small percentage of traffic to it — 1%, then 5%, then 25%, then 100%. At each stage, you watch metrics. If something breaks, you stop the rollout and the 99% on the old version is unaffected.

Stage 1:  99% → [v1.2]   1% → [v1.3]
Stage 2:  90% → [v1.2]  10% → [v1.3]
Stage 3:  50% → [v1.2]  50% → [v1.3]
Stage 4:   0% → [v1.2] 100% → [v1.3]   (done)
Rollback: 100% → [v1.2]   0% → [v1.3]   (instant, no redeploy)

Pros:

  • Risk is proportional. A bad deploy affects 1% of users, not 100%. You catch regressions with real traffic before they hit everyone.
  • No 2x infra cost. You run N instances of v1.2 and M of v1.3; the total is the same as before, just split.
  • Gradual capacity validation. If the new version has a memory leak, you see it at 5% before it takes down the fleet at 100%.
  • Works with stateful services. Each version's instances handle their own sessions; no atomic switch.

Cons:

  • Rollback isn't instant for affected users. The 5% who hit the bug are affected until you shift traffic back. (Though this is minutes, not hours.)
  • Requires traffic-routing infrastructure. A load balancer or service mesh that can do weighted routing. Kubernetes, Istio, Envoy, and most cloud load balancers support this natively.
  • Observability must be version-aware. You need to slice metrics by version, or you can't tell if v1.3 is the problem. This means tagging logs, metrics, and traces with the version.
  • Database migrations are still hard. Same as blue-green: two versions running simultaneously need backward-compatible schemas.

When to use canary:

  • You have a load balancer / service mesh that supports weighted routing.
  • Your app has real users (the whole point is catching issues with real traffic).
  • You can slice metrics by version.
  • You want to minimize blast radius over instant rollback.

The database migration problem (both strategies)

This is the part most explainers skip. Both blue-green and canary run two versions simultaneously, which means both versions must work against the same database schema. A migration that drops a column v1.2 needs will break v1.2 the moment it runs.

The solution is expand-and-contract migrations:

  1. Expand: Add the new schema (new column, new table) without removing the old. Both versions run.
  2. Migrate: Deploy v1.3, which writes to both old and new schema. Backfill the new schema from the old.
  3. Contract: Once v1.2 is fully retired, drop the old schema.

This takes discipline and usually spans multiple deploys. But it's the only safe way to migrate schemas while running two versions. Skipping it is how teams end up with 3am "emergency rollback failed because the schema changed" incidents.

Which should you actually use?

For a small team / early-stage SaaS: canary.

Canary gives you the most safety per dollar. You don't pay for 2x infra, you catch real-world regressions, and modern platforms (Vercel, Railway, Fly.io, Kubernetes) make weighted routing trivial. The observability requirement (version-tagged metrics) is something you should build anyway.

For a team that values instant rollback above cost: blue-green.

If you're running an infrastructure-heavy service where a bad deploy = data corruption = catastrophic, blue-green's atomic switch and instant rollback are worth the 2x cost. This is common in fintech, healthcare, and anything with irreversible side effects.

For everyone: feature flags on top of either.

Both strategies deploy code. Neither controls features. Feature flags let you deploy code that's off, turn it on for 1% of users, watch, expand to 100%, and kill it instantly if it breaks — without a redeploy. Pair flags with whichever deploy strategy you choose.

The anti-pattern: rolling deploys without canary

A surprising number of teams do "rolling deploys" — replace instances one at a time — and call it safe. It's not. A rolling deploy with a bad version affects every instance eventually; you just discover it slower. If you're going rolling, add canary on top: roll to 1% first, watch, then continue.

Run the checklist

The ShipReady CI/CD section covers both: "Blue-green or canary deployments" and "Rollback plan" are separate items because they're separate concerns. The Reliability section's "Database backups + tested restore drills" matters here too — your migration strategy is only as safe as your ability to restore when it breaks.

Run the checklist before your next deploy. Your future self, at 3am deciding whether to roll back, will thank you.

Run the full checklist

Put this into practice — generate a stack-specific production readiness checklist and track your progress, free.

Open the checklist

Get new articles in your inbox

Practical production readiness guides. No spam, unsubscribe anytime.

Join developers shipping safer. We email ~2× per month.

Keep reading