Skip to main content

Canary Releases and Blue-Green Deployments in React

Canary releases and blue-green deployments are deployment strategies that reduce the blast radius when bugs slip through code review. A canary release gradually shifts traffic to new code: 1% first, 5%, 25%, 100%. Blue-green deploys two identical production environments and switch traffic between them, allowing instant rollback. This article compares both, explains when to use each, and shows how to implement them alongside feature flags.

In 2021, my team deployed a React bundler config change at 3 PM Friday (worst time). Within 10 seconds, 30% of users hit a JavaScript error in the new bundle. Without a canary or blue-green setup, we had a 15-minute incident while we reverted. With a canary, that change would have hit 1% of users, we would have seen errors in monitoring, and rolled back in 30 seconds. Now, we never deploy at 100% on the first pass.

Deployment Strategies Compared

StrategyRollout TimeDowntimeRollback SpeedRiskComplexity
Big Bang (100%)1 minute~30 sec10+ minVery HighLow
Canary (1-100%)30+ min0 sec~30 secLowMedium
Blue-Green1 minute~5 sec~5 secLowHigh
Shadow TrafficAsync0 sec0 sec (read-only)Very LowVery High

Big Bang (100%): All users get new code at once. Fast but risky; if bugs exist, everyone hits them simultaneously.

Canary (1% → 5% → 25% → 100%): Gradually shift traffic to new code, monitoring at each step. Safe but slow.

Blue-Green: Two production environments (blue and green). Deploy to the inactive environment, test, then switch router to send traffic to the new environment. Instant rollback by switching back.

Shadow Traffic: Send a copy of production traffic to new code but discard the response (read-only). Users don't see the new code, but you measure performance and error rates.

For React SPAs, canary releases are most practical. They require feature flags to switch variants at runtime, but no infrastructure changes (no second production environment). Blue-green deployments are common in backend services, but for frontend SPAs, they add complexity without much benefit (you can't easily run two copies of your SPA on the same domain).

Canary Release Architecture

A canary release uses feature flags to gradually expose new code to users. The deployment pipeline looks like this:

1. Deploy new code to production (with feature flag OFF for all)
2. Enable flag for 1% of users
3. Monitor error rates, latency, business metrics for 15 minutes
4. If OK, enable for 5% of users
5. Monitor for 15 minutes
6. If OK, enable for 25%, then 50%, then 100%
7. Keep the flag as an ops toggle for 24 hours (kill switch if needed)
8. Delete the flag

Your feature flag config service has a release_feature_name flag with rules like:

{
"flagName": "release_checkout_v2",
"enabled": true,
"rules": [
{
"name": "Canary 1%",
"condition": {},
"percentage": 1
}
]
}

Every 15 minutes, you increment the percentage (1% → 5% → 25% → 50% → 100%) and watch your observability dashboards.

Monitoring During Canary

Canary success depends on good monitoring. You need dashboards tracking:

  1. Error rate by flag variant: Count errors in the control and new variant separately. If new variant errors > 2x baseline, roll back.

  2. Latency (p95, p99): If new code is slower, you'll see latency increase. Alert if p99 latency increases > 100 ms.

  3. Business metrics: Conversion rate, checkout success, API success rate. If you're rolling out a checkout redesign, watch checkout success closely.

  4. Structured logs: Every error or slow request should log the flag variant. This helps you correlate issues to the new code.

Example Datadog query for canary monitoring:

avg:app.checkout.latency{flag:release_checkout_v2:variant}
/ avg:app.checkout.latency{flag:release_checkout_v2:control}

This shows the ratio of latency for the new variant vs control. If the ratio is > 1.2 (20% slower), alert.

Implementing Canary with Feature Flags

In your deployment pipeline (GitHub Actions, GitLab CI, etc.), add a script that increments the flag percentage:

#!/bin/bash
# deploy-canary.sh
# Usage: ./deploy-canary.sh feature_checkout_v2

FLAG_NAME=$1
PERCENTAGES=(1 5 25 50 100)

for PCT in "${PERCENTAGES[@]}"; do
echo "Rolling out $FLAG_NAME to $PCT%..."

# Call your flag service API to update the flag
curl -X POST https://flags.example.com/api/flags/$FLAG_NAME \
-H "Authorization: Bearer $FLAG_SERVICE_TOKEN" \
-d "{\"percentage\": $PCT}"

# Wait and monitor
echo "Waiting 15 minutes for monitoring..."
sleep 900

# Check error rate
ERROR_RATE=$(curl -s https://observability.example.com/api/errors \
--data-urlencode "flag=$FLAG_NAME&variant=variant" | jq '.error_rate')

if (( $(echo "$ERROR_RATE > 0.05" | bc -l) )); then
echo "Error rate $ERROR_RATE > 5%. Rolling back..."
curl -X POST https://flags.example.com/api/flags/$FLAG_NAME \
-H "Authorization: Bearer $FLAG_SERVICE_TOKEN" \
-d "{\"percentage\": 0}"
exit 1
fi
done

echo "Canary complete. Flag now at 100%."

Alternatively, manually step through percentages if you prefer human judgment at each stage. Automated canaries are faster but riskier if your monitoring is noisy.

Blue-Green Deployments for React

Blue-green is less common for React SPAs, but it's useful if you're deploying both frontend and backend changes simultaneously. The pattern:

  1. Current state: Blue environment is live (users → blue).
  2. Deploy: Deploy new code to green environment.
  3. Test: Run smoke tests against green (no users).
  4. Switch: Router sends traffic from blue to green.
  5. Monitor: Watch green for errors.
  6. Rollback: If issues, switch back to blue.

For a React SPA, blue and green are two versions of your built static files, hosted on different CDN cache keys or paths:

Blue:  /app/v1/ (current live version)
Green: /app/v2/ (new version being deployed)

Your load balancer or CDN edge routes traffic based on a flag or header. If green is healthy, you keep the routing rule. If problems appear, you flip it back to blue.

Practical for React: Blue-green is most useful if you have a complex backend coordination or want instant rollback without relying on feature flags. But for SPA-only changes, canary is simpler.

Combining Canary and Blue-Green

For maximum safety, combine both:

  1. Deploy new code with a feature flag OFF (canary preparation).
  2. Gradually enable the flag for 1%, 5%, 25%, 50%, 100% (canary release).
  3. If you need instant rollback at any point, switch the blue-green router back to the old code (blue), then investigate the new code (green) offline.

This gives you both gradual exposure (canary) and instant rollback (blue-green). The cost is higher infrastructure complexity, but for critical systems, it's worth it.

Key Takeaways

  • Canary releases gradually roll out new code via feature flags, monitoring at each step (1% → 5% → 25% → 50% → 100%).
  • Blue-green deployments run two production environments and switch traffic between them, enabling instant rollback.
  • For React SPAs, canary is simpler and more practical (no need for dual infrastructure).
  • During canary, monitor error rates, latency, and business metrics. Rollback if any metric degrades > 2x.
  • Automated canaries can speed up rollouts; manual canaries give you more control and reduce the risk of rolling out during a monitoring glitch.
  • Combine canary and blue-green for maximum safety: gradual rollout + instant kill switch.

Frequently Asked Questions

How long should each canary step take?

At least 15 minutes, ideally 30. This captures enough user behavior to see errors. If you see errors in the first 5 minutes, they'll likely reappear at higher percentages. Conversely, 15 minutes is enough to be confident that a rare error (0.1% chance) hasn't hidden itself.

What if I'm deploying at 3 AM and no one is monitoring?

Don't. Deploy during business hours when people are watching dashboards. If you must deploy off-hours, use a blue-green switch to minimize blast radius, and set up automated alerts that wake the on-call engineer if error rates spike.

How do I handle state changes during blue-green switch?

This is the hard part of blue-green: if your old code (blue) and new code (green) have incompatible database schema or cache structures, switching between them can cause data corruption. For React SPAs, this is less of an issue (the frontend is stateless), but if your backend schema changed, be careful. Usually, you deploy schema changes to the database first (in a backward-compatible way), then deploy the new code (green), then switch.

Can I run canary and regular A/B tests simultaneously?

Yes, but you need non-overlapping feature flags. A canary flag (release_checkout_v2) controls the rollout; an experiment flag (exp_checkout_cta_size) controls which variant users see within the canary population. Users in both control and variant see the new checkout (canary: 25%), and within that 25%, half see CTA variant A, half variant B (experiment).

How do I alert on canary failures?

Set up an alert in your observability platform that fires if error_rate(variant) > 2 * error_rate(control) or latency_p99(variant) > latency_p99(control) + 100ms. This is a conditional alert: only within the context of a running canary.

Further Reading