The Problem
Our deployment anxiety was high:
- Every deploy was a potential incident
- Rollbacks required full redeployment (5-10 minutes)
- No way to test features with subset of users
- Product couldn’t run A/B tests
Feature Flag Strategy
We established patterns for flag usage:
Release Flags: Temporary flags for new features
if (flags.isEnabled('new-checkout-flow', user)) {
return newCheckoutFlow();
}
return legacyCheckoutFlow();
Ops Flags: Permanent flags for operational control
if (flags.isEnabled('enable-cache', { service: 'api' })) {
return cachedResponse();
}
Experiment Flags: For A/B testing
const variant = flags.getVariant('pricing-test', user);
return pricingPages[variant];
Rollout Process
New features now follow this process:
- Deploy with flag disabled (0%)
- Enable for internal users (dogfooding)
- Enable for 1% of users, monitor
- Gradually increase: 5% → 25% → 50% → 100%
- Remove flag after feature is stable
Results
- Deployment frequency: 3x increase (less fear)
- Incident recovery time: 90% reduction (instant kill switch)
- A/B tests run: 12 in first quarter (previously 0)
- Developer confidence: Significantly improved
The $500/month cost has paid for itself many times over in reduced incident impact and faster iteration.
Lessons Learned
- Flag hygiene matters: We schedule flag cleanup to avoid technical debt
- Default to off: New flags should be disabled by default
- Document flag purpose: Every flag needs an owner and expiration date