$npx -y skills add girijashankarj/cursor-handbook --skill feature-flag-managerCreate, manage, and clean up feature flags for gradual rollouts and safe deployments. Use when the user asks to add a feature flag, toggle, or manage feature gating.
| 1 | # Skill: Feature Flag Manager |
| 2 | |
| 3 | Implement feature flags for controlled rollouts, A/B testing, and safe deployments with cleanup workflows. |
| 4 | |
| 5 | ## Trigger |
| 6 | When the user asks to add a feature flag, gate a feature, set up gradual rollout, or clean up old flags. |
| 7 | |
| 8 | ## Prerequisites |
| 9 | - [ ] Feature to gate identified |
| 10 | - [ ] Rollout strategy decided (on/off, percentage, user segment) |
| 11 | |
| 12 | ## Steps |
| 13 | |
| 14 | ### Step 1: Choose Flag Strategy |
| 15 | |
| 16 | | Strategy | When to Use | Complexity | |
| 17 | |----------|-------------|-----------| |
| 18 | | **Boolean toggle** | Simple on/off per environment | Low | |
| 19 | | **Percentage rollout** | Gradual rollout to % of users | Medium | |
| 20 | | **User segment** | Specific users, orgs, or roles | Medium | |
| 21 | | **A/B test** | Compare variants with metrics | High | |
| 22 | | **Kill switch** | Emergency disable of a feature | Low | |
| 23 | |
| 24 | ### Step 2: Define the Flag |
| 25 | - [ ] Name: `FEATURE_{DOMAIN}_{DESCRIPTION}` (e.g., `FEATURE_ORDERS_ASYNC_PROCESSING`) |
| 26 | - [ ] Type: boolean, number (percentage), string (variant) |
| 27 | - [ ] Default value: `false` (new features default to off) |
| 28 | - [ ] Description: one sentence explaining what it controls |
| 29 | - [ ] Owner: team or person responsible |
| 30 | - [ ] Expiry: target date for cleanup |
| 31 | |
| 32 | ### Step 3: Create Flag Configuration |
| 33 | |
| 34 | ```typescript |
| 35 | // config/feature-flags.ts |
| 36 | export const FeatureFlags = { |
| 37 | FEATURE_ORDERS_ASYNC_PROCESSING: { |
| 38 | key: 'FEATURE_ORDERS_ASYNC_PROCESSING', |
| 39 | description: 'Enable async order processing pipeline', |
| 40 | defaultValue: false, |
| 41 | owner: 'orders-team', |
| 42 | createdAt: '2026-04-12', |
| 43 | targetCleanup: '2026-06-12', |
| 44 | }, |
| 45 | } as const; |
| 46 | |
| 47 | export type FeatureFlagKey = keyof typeof FeatureFlags; |
| 48 | ``` |
| 49 | |
| 50 | ### Step 4: Implement Flag Check Utility |
| 51 | |
| 52 | ```typescript |
| 53 | // utils/feature-flags.ts |
| 54 | export function isFeatureEnabled( |
| 55 | flagKey: FeatureFlagKey, |
| 56 | context?: { userId?: string; orgId?: string } |
| 57 | ): boolean { |
| 58 | const envValue = process.env[flagKey]; |
| 59 | if (envValue !== undefined) { |
| 60 | return envValue === 'true' || envValue === '1'; |
| 61 | } |
| 62 | return FeatureFlags[flagKey].defaultValue; |
| 63 | } |
| 64 | ``` |
| 65 | |
| 66 | ### Step 5: Gate the Feature in Code |
| 67 | |
| 68 | ```typescript |
| 69 | // In handler/service: |
| 70 | if (isFeatureEnabled('FEATURE_ORDERS_ASYNC_PROCESSING', { userId })) { |
| 71 | await processOrderAsync(order); |
| 72 | } else { |
| 73 | await processOrderSync(order); |
| 74 | } |
| 75 | ``` |
| 76 | |
| 77 | ### Step 6: Add to Environment Config |
| 78 | - [ ] Add flag to `.env.example` with `false` default |
| 79 | - [ ] Add to staging `.env` with `true` for testing |
| 80 | - [ ] Keep production as `false` until ready for rollout |
| 81 | |
| 82 | ### Step 7: Add Tests for Both Paths |
| 83 | - [ ] Test with flag enabled |
| 84 | - [ ] Test with flag disabled |
| 85 | - [ ] Test flag default behavior (env var not set) |
| 86 | |
| 87 | ```typescript |
| 88 | describe('when FEATURE_ORDERS_ASYNC_PROCESSING is enabled', () => { |
| 89 | beforeEach(() => { process.env.FEATURE_ORDERS_ASYNC_PROCESSING = 'true'; }); |
| 90 | afterEach(() => { delete process.env.FEATURE_ORDERS_ASYNC_PROCESSING; }); |
| 91 | |
| 92 | it('should process order asynchronously', async () => { /* ... */ }); |
| 93 | }); |
| 94 | |
| 95 | describe('when FEATURE_ORDERS_ASYNC_PROCESSING is disabled', () => { |
| 96 | it('should process order synchronously', async () => { /* ... */ }); |
| 97 | }); |
| 98 | ``` |
| 99 | |
| 100 | ### Step 8: Document Rollout Plan |
| 101 | ```markdown |
| 102 | ## Rollout Plan: FEATURE_ORDERS_ASYNC_PROCESSING |
| 103 | 1. **Dev/Staging**: Enable, run integration tests |
| 104 | 2. **Canary (5%)**: Monitor error rate and latency for 24h |
| 105 | 3. **Gradual (25% → 50% → 100%)**: Each stage monitored for 48h |
| 106 | 4. **Cleanup**: Remove flag after 2 weeks at 100% |
| 107 | ``` |
| 108 | |
| 109 | ## Flag Cleanup Workflow |
| 110 | |
| 111 | ### When to Clean Up |
| 112 | - Flag has been at 100% for 2+ weeks |
| 113 | - No incidents related to the feature |
| 114 | - Target cleanup date reached |
| 115 | |
| 116 | ### Cleanup Steps |
| 117 | 1. Remove the flag check — keep the "enabled" code path |
| 118 | 2. Remove the "disabled" code path |
| 119 | 3. Remove flag from `FeatureFlags` config |
| 120 | 4. Remove from `.env` files |
| 121 | 5. Remove flag-specific tests (keep the feature tests) |
| 122 | 6. Update documentation |
| 123 | |
| 124 | ## Rules |
| 125 | - **ALWAYS** default new flags to `false` (off) |
| 126 | - **ALWAYS** set a cleanup target date when creating a flag |
| 127 | - **ALWAYS** test both code paths (enabled and disabled) |
| 128 | - **NEVER** nest feature flags (flag inside flag) |
| 129 | - **NEVER** use feature flags for permanent configuration — use config instead |
| 130 | - Flag names must be descriptive and follow `FEATURE_DOMAIN_DESCRIPTION` pattern |
| 131 | - Maximum 15 active flags at any time — clean up before adding more |
| 132 | |
| 133 | ## Completion |
| 134 | Feature flag created with config, utility function, code gating, tests, and rollout plan. Cleanup date documented. |
| 135 | |
| 136 | ## If a Step Fails |
| 137 | - **Too many active flags:** Audit and clean up stale flags first |
| 138 | - **Complex branching:** Consider a feature flag service (LaunchDarkly, Unleash) instead of env vars |
| 139 | - **Tests flaky with flag:** Ensure env var cleanup in `afterEach` |
| 140 | - **Can't determine rollout strategy:** Default to boolean toggle, upgrade later |