vt-c-feature-flags¶
Implement safe progressive rollouts using feature flags. Covers flag lifecycle, percentage rollouts, A/B testing, and kill switches for production safety.
Plugin: core-standards
Category: Operations
Command: /vt-c-feature-flags
Feature Flags Skill¶
Purpose: Enable safe, gradual feature releases with instant rollback capability. Feature flags decouple deployment from release, reducing deployment risk.
Why Feature Flags¶
Without feature flags: - Releases are all-or-nothing - Rollback requires redeployment - No way to test in production safely - Can't do A/B testing
With feature flags: - Release to 1% of users first - Instant kill switch for problems - Target specific users for testing - Measure impact before full rollout
Tool Recommendations¶
| Tool | Best For | Pricing |
|---|---|---|
| LaunchDarkly | Enterprise, complex targeting | Per-seat |
| Unleash | Self-hosted, open source | Free (self-hosted) |
| Flipper (Ruby) | Rails applications | Free |
| Flagsmith | Open source, hosted option | Free tier |
| PostHog | Feature flags + analytics | Free tier |
Implementation Patterns¶
Basic Flag Check¶
// ✅ GOOD - Clean flag check
if (featureFlags.isEnabled('new-checkout')) {
return <NewCheckout />;
}
return <OldCheckout />;
Percentage Rollout¶
// LaunchDarkly example
const showNewFeature = ldClient.variation(
'new-feature',
{ key: user.id },
false // default
);
// Unleash example
const showNewFeature = unleash.isEnabled('new-feature', {
userId: user.id,
});
User Targeting¶
// Target specific users (beta testers)
const context = {
key: user.id,
email: user.email,
custom: {
plan: user.plan,
company: user.companyId,
},
};
const showFeature = ldClient.variation('feature-x', context, false);
Flag Lifecycle¶
1. Creation¶
flag:
key: new-checkout-flow
name: "New Checkout Flow"
description: "Redesigned checkout with fewer steps"
type: boolean
defaultValue: false
tags: [checkout, ux, q4-release]
2. Development (Off)¶
- Feature behind flag
- Only enabled in development
- Tests cover both paths
3. Internal Testing¶
- Enable for team members
- QA in staging environment
4. Beta Rollout¶
- Enable for beta users (1-5%)
- Monitor error rates and feedback
5. Progressive Rollout¶
Day 1: 1% of users
Day 2: 5% of users (if metrics good)
Day 3: 25% of users
Day 4: 50% of users
Day 5: 100% of users
6. Cleanup¶
- Remove flag from code
- Delete flag from dashboard
- Critical: Don't leave stale flags!
Kill Switch Pattern¶
For critical features, implement instant disable:
// Kill switch - checked on every request
const isSystemHealthy = featureFlags.isEnabled('system-healthy');
if (!isSystemHealthy) {
return <MaintenancePage />;
}
// Feature-specific kill switch
const checkoutEnabled = featureFlags.isEnabled('checkout-enabled');
if (!checkoutEnabled) {
return <CheckoutUnavailable />;
}
A/B Testing Pattern¶
// Get variant instead of boolean
const variant = featureFlags.variation('pricing-page', user, 'control');
switch (variant) {
case 'control':
return <PricingPageA />;
case 'variant-b':
return <PricingPageB />;
case 'variant-c':
return <PricingPageC />;
default:
return <PricingPageA />;
}
// Track conversion
analytics.track('pricing-view', { variant });
Best Practices¶
DO¶
// ✅ Use meaningful flag names
'new-checkout-flow'
'enable-dark-mode'
'show-promo-banner-q4'
// ✅ Have defaults
const enabled = flags.get('feature', false);
// ✅ Test both states
describe('Feature X', () => {
it('shows new UI when enabled', () => { ... });
it('shows old UI when disabled', () => { ... });
});
// ✅ Clean up old flags
// TODO: Remove after 2024-03-01
if (flags.isEnabled('old-feature')) { ... }
DON'T¶
// ❌ Generic names
'feature-1'
'test-flag'
// ❌ No default (crashes if flag missing)
const enabled = flags.get('feature');
// ❌ Complex nested flags
if (flagA && (flagB || !flagC)) { ... }
// ❌ Business logic in flags
if (flags.get('price-' + product.id)) { ... }
Monitoring Flags¶
Track Flag Evaluations¶
// Log flag decisions for debugging
featureFlags.on('flag-evaluated', (key, value, context) => {
analytics.track('flag-evaluation', {
flag: key,
value,
userId: context.key,
});
});
Alert on Flag Changes¶
# PagerDuty/Opsgenie rule
alert:
name: "Kill switch activated"
condition: "flag.checkout-enabled changed to false"
action: "notify team"
Integration with Toolkit¶
Before Deployment¶
## Pre-Deploy Flag Checklist
- [ ] New feature behind flag?
- [ ] Flag default is OFF (safe)?
- [ ] Kill switch identified?
- [ ] Rollout plan documented?
- [ ] Both code paths tested?
Rollout Plan Template¶
## Rollout Plan: [Feature Name]
**Flag key:** `new-feature-x`
**Kill switch:** `feature-x-enabled`
### Rollout Schedule
| Day | Percentage | Duration | Success Criteria |
|-----|------------|----------|------------------|
| 1 | 1% | 24h | Error rate < 0.1% |
| 2 | 5% | 24h | No critical bugs |
| 3 | 25% | 48h | Metrics baseline |
| 4 | 100% | - | Full release |
### Rollback Triggers
- Error rate > 1%
- P95 latency > 2x baseline
- Support tickets spike
### Rollback Process
1. Disable flag in dashboard
2. Verify old behavior restored
3. Notify team
4. Investigate issue