Skip to main content

Progressive Rollouts and Gradual Feature Release in React

A progressive rollout is the safest way to release a feature: start small (1% of users), monitor for errors and regressions, then expand in stages (5%, 10%, 50%, 100%). At each stage, you make a go/no-go decision based on data. This article covers designing robust progressive rollout workflows, what metrics to monitor, and automating the process.

I've seen teams deploy features in binary fashion: either 0% of users or 100%. That works fine most of the time, but when something breaks (maybe 1 in 500 times), it breaks for everyone simultaneously. In 2020, a new analytics library corrupted user profiles for 10% of users (a subtle bug that manifested only for users with non-ASCII characters in their names). With a progressive rollout, we'd have caught it at 1% in 15 minutes. Instead, we caught it after 3 hours and affected 50k users. Progressive rollouts are not optional once you're at scale.

The Progressive Rollout Process

A progressive rollout typically follows this pattern:

Day 1 (Morning):  Deploy code (flag OFF), then enable for 1% of users
Monitor for 30 minutes
Day 1 (Afternoon): Error rate and metrics look good, expand to 5%
Day 2 (Morning): Still good, expand to 10%
Day 2 (Evening): Expand to 25%
Day 3 (Morning): Expand to 50%
Day 3 (Evening): Expand to 100% (fully live)
Day 4: Keep flag as kill switch for 24 hours, then delete

The timing is flexible. For low-risk changes (CSS tweaks), you can go 0% → 100% in 1 hour. For high-risk changes (payment processing, auth), slow down: 24+ hours at each stage.

What to Monitor at Each Stage

At each rollout stage, you need guardrails: metrics that must stay healthy. If they don't, you rollback immediately.

Critical Metrics

MetricBaselineAlert ThresholdWhy It Matters
Error rate (5xx responses)0.5%> 2%Silent failures, broken features
Latency (p99)200 ms> 300 msSlow feature impacts UX
Database query time50 ms> 100 msSlow queries = scalability issues
API error rate2%> 5%Third-party integrations failing
Revenue / conversion rate4%< 3.5% (0.5 point)Feature breaks user flow
Session duration5 min< 4 minUsers leaving early

Where to Find These Metrics

  • Error rate: Sentry, Datadog, New Relic. Filter by feature flag to isolate the variant.
  • Latency: Application Performance Monitoring (APM) tools. Look at both frontend (user experience) and backend (server load).
  • Revenue/conversion: Analytics platform (Amplitude, Mixpanel). Track conversion rate separately for control and variant.
  • Database load: Database monitoring. Check slow query logs and connection pool saturation.
  • API health: AWS CloudWatch, Azure Monitor, or your API gateway logs.

Setting Up Automated Monitoring

Manually checking metrics at each stage is error-prone. Automate it with a monitoring dashboard and alerts.

Example Datadog dashboard for a progressive rollout:

# Datadog dashboard config
dashboard:
title: "Checkout V2 Progressive Rollout"
widgets:
- title: "Error Rate by Variant"
query: |
avg:app.errors{flag:release_checkout_v2:*} by {flag:release_checkout_v2}
- title: "Latency (p99) by Variant"
query: |
p99:app.latency{flag:release_checkout_v2:*} by {flag:release_checkout_v2}
- title: "Conversion Rate by Variant"
query: |
avg:app.checkout.completed{flag:release_checkout_v2:*} by {flag:release_checkout_v2}
- title: "Database Query Time"
query: |
avg:db.query.time{flag:release_checkout_v2:variant}

Alerts:

alerts:
- name: "Checkout V2: Error rate spike"
query: "avg:app.errors{flag:release_checkout_v2:variant} > 2%"
notify: "@pagerduty-oncall"

- name: "Checkout V2: Latency increase"
query: "p99:app.latency{flag:release_checkout_v2:variant} > 300ms"
notify: "@slack-devops"

Decision Workflow: Go vs No-Go at Each Stage

At each rollout stage, you make a decision based on monitoring data. Here's a template:

Stage Start Time: 2026-06-02 08:00 UTC
Stage Percentage: 1%
Estimated Users: ~100,000

Metrics Check (after 30 minutes):
✓ Error rate (variant): 0.8% (baseline: 0.5%, threshold: 2%) → PASS
✓ Latency p99: 210 ms (baseline: 200 ms, threshold: 300 ms) → PASS
✓ Conversion rate: 4.1% (baseline: 4.0%, threshold: no regression) → PASS
✓ Database query time: 52 ms (baseline: 50 ms, threshold: 100 ms) → PASS
✗ Payment API errors: 3.2% (baseline: 2%, threshold: 5%) → MARGINAL
- Investigation: Upstream provider has 99.8% uptime today, no issue on our side
- Decision: Accept the marginal alert, likely unrelated to our change

Overall: GO. Expand to 5%.

Stage Notes:
- One user reported slow checkout in chat, but they're on a 3G connection. Likely not related.
- All critical metrics are healthy.
- Next stage: expand to 5% at 10:00 UTC.

Go criteria:

  • Error rate does not increase by > 2x.
  • Latency does not increase by > 50%.
  • No regressions in business metrics (conversion, revenue).
  • No new patterns in error logs (same errors as baseline, not new errors).

No-Go criteria (rollback immediately):

  • Error rate spikes to > 5%.
  • Latency increases by > 100%.
  • Conversion rate drops by > 1 percentage point.
  • Security/data corruption detected in logs.

Automated Progressive Rollout

You can automate the entire process using a CI/CD pipeline. A script monitors metrics and automatically expands the flag percentage.

#!/bin/bash
# auto-rollout.sh - Automated progressive rollout

FLAG_NAME="release_checkout_v2"
PERCENTAGES=(1 5 10 25 50 100)
STAGE_DURATION_MIN=30

for PCT in "${PERCENTAGES[@]}"; do
echo "=== Progressive Rollout: $PCT% ==="

# Update flag percentage via flag service API
curl -X POST "https://flags.example.com/api/flags/$FLAG_NAME" \
-H "Authorization: Bearer $FLAG_SERVICE_TOKEN" \
-d "{\"percentage\": $PCT, \"rollout_stage\": $PCT}"

echo "Waiting $STAGE_DURATION_MIN minutes for monitoring..."
sleep $((STAGE_DURATION_MIN * 60))

# Query metrics from monitoring service
ERROR_RATE=$(curl -s "https://monitoring.example.com/metrics/error-rate" \
--data-urlencode "flag=$FLAG_NAME&variant=variant" | jq '.error_rate')

LATENCY_P99=$(curl -s "https://monitoring.example.com/metrics/latency" \
--data-urlencode "flag=$FLAG_NAME&percentile=99" | jq '.latency_ms')

CONVERSION_RATE=$(curl -s "https://monitoring.example.com/metrics/conversion" \
--data-urlencode "flag=$FLAG_NAME&variant=variant" | jq '.conversion_rate')

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

if (( $(echo "$LATENCY_P99 > 300" | bc -l) )); then
echo "ABORT: Latency p99 $LATENCY_P99 > 300 ms"
curl -X POST "https://flags.example.com/api/flags/$FLAG_NAME" \
-H "Authorization: Bearer $FLAG_SERVICE_TOKEN" \
-d "{\"percentage\": 0}"
exit 1
fi

echo "GO: Error rate $ERROR_RATE, Latency $LATENCY_P99 ms, Conversion $CONVERSION_RATE. Proceeding to next stage."
done

echo "=== Rollout Complete at 100% ==="

Run this script after deploying new code. It monitors and automatically expands, or stops and rolls back if something breaks.

Rollback Strategy

If any metric fails, rollback immediately:

  1. Instant disable: Set flag percentage to 0% (off for all users).
  2. Immediate notification: Alert the engineering and product teams.
  3. Rootcause investigation: Check error logs for the variant-specific errors.
  4. Fix and re-deploy: Fix the bug, commit, deploy new code, and re-start the rollout.

Rollback should be reversible and quick. If you can't rollback the code in 5 minutes, your system isn't mature. Use feature flags, blue-green deployments, and database rollback scripts to be reversible.

Key Takeaways

  • Progressive rollouts follow a pattern: 1% → 5% → 10% → 25% → 50% → 100%, with monitoring and go/no-go decisions at each stage.
  • Monitor error rate, latency, and business metrics (conversion, revenue) at each stage.
  • Rollback immediately if any metric regresses by > 2x or if error rates spike.
  • Automate the process with a script that monitors metrics and expands the flag percentage automatically.
  • Keep rollbacks reversible: use feature flags, not database migrations, as the primary deployment mechanism.

Frequently Asked Questions

How long should each stage last?

At least 15–30 minutes for high-traffic apps (captures enough user sessions). For low-traffic apps, 1–2 hours. For mission-critical systems (payments), 24+ hours per stage. The longer you wait, the more confident you are that no rare bugs exist.

What if metrics are noisy (high variance)?

Use statistical significance testing. For conversion rate, check if the 95% confidence interval for the variant overlaps with the control (as described in the statistical analysis article). If they overlap, the result is inconclusive; wait longer before expanding.

Can I skip stages if I'm confident in my testing?

Yes, but at your own risk. Skipping stages reduces blast radius on failure but increases time-to-value. A safe compromise: always do 1% (catches deployment issues, typos), then jump to 50%, then 100%. Never skip the 1% stage.

How do I coordinate progressive rollouts across multiple teams?

Use a release train: all teams roll out their features on the same schedule (e.g., Tuesday 10 AM UTC). A shared on-call team monitors all flags simultaneously. This prevents too many rollouts at once and makes post-mortems simpler.

What if a progressive rollout starts but gets interrupted (engineer leaves, server crash)?

The flag percentage stays where it was last set. If interrupted mid-rollout, resume from that percentage (or rollback to 0% if unsure). Always document the current rollout state in a shared runbook or issue so team members know the status.

Further Reading