8 min read • Guide 759 of 877
Feature Flags Management with GitScrum
Feature flags decouple deployment from release. GitScrum helps teams track flag-controlled features and coordinate rollouts effectively.
Feature Flag Basics
What Flags Enable
FEATURE FLAG USE CASES:
┌─────────────────────────────────────────────────────────────┐
│ │
│ GRADUAL ROLLOUT: │
│ Deploy to 1% → 10% → 50% → 100% │
│ Monitor metrics at each stage │
│ Roll back instantly if issues │
│ │
│ DARK LAUNCHING: │
│ Code deployed but hidden from users │
│ Enables integration testing in production │
│ No risk to users │
│ │
│ A/B TESTING: │
│ 50% see version A, 50% see version B │
│ Measure which performs better │
│ Data-driven decisions │
│ │
│ KILL SWITCH: │
│ Disable problematic feature instantly │
│ No deployment needed │
│ Minutes vs hours to respond │
│ │
│ BETA ACCESS: │
│ Enable for specific users/customers │
│ Gather feedback before wide release │
│ Premium feature access control │
│ │
│ OPERATIONAL CONTROLS: │
│ Enable/disable expensive features under load │
│ Graceful degradation │
│ Circuit breakers │
│ │
│ TRUNK-BASED DEVELOPMENT: │
│ Incomplete features behind flags │
│ Merge to main frequently │
│ No long-lived feature branches │
└─────────────────────────────────────────────────────────────┘
Flag Types
Categorizing Flags
FEATURE FLAG TYPES:
┌─────────────────────────────────────────────────────────────┐
│ │
│ RELEASE FLAGS (Short-lived): │
│ ───────────────────────────── │
│ Purpose: Control new feature rollout │
│ Lifespan: Days to weeks │
│ Example: new_dashboard_enabled │
│ │
│ Create → Rollout → Remove │
│ MUST be removed after 100% rollout │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ EXPERIMENT FLAGS (Short-lived): │
│ ─────────────────────────────── │
│ Purpose: A/B testing │
│ Lifespan: Duration of experiment │
│ Example: checkout_flow_experiment │
│ │
│ Create → Run experiment → Pick winner → Remove │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ PERMISSION FLAGS (Long-lived): │
│ ────────────────────────────── │
│ Purpose: Entitlement/feature access │
│ Lifespan: Permanent or product lifecycle │
│ Example: premium_analytics_enabled │
│ │
│ These are essentially product features │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ OPERATIONAL FLAGS (Long-lived): │
│ ──────────────────────────────── │
│ Purpose: System behavior control │
│ Lifespan: Permanent │
│ Example: enable_caching, rate_limit_mode │
│ │
│ Used for ops, not features │
└─────────────────────────────────────────────────────────────┘
Flag Lifecycle
Creating Flags
FLAG CREATION WORKFLOW:
┌─────────────────────────────────────────────────────────────┐
│ │
│ WHEN TO CREATE FLAG: │
│ │
│ During development: │
│ • New user-facing feature │
│ • Risky change │
│ • Cross-team dependency │
│ • Feature needing gradual rollout │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ FLAG NAMING CONVENTION: │
│ │
│ Format: [scope]_[feature]_[type] │
│ │
│ Examples: │
│ • dashboard_new_charts_release │
│ • checkout_one_click_experiment │
│ • premium_analytics_permission │
│ • cache_disable_operational │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ GITSCRUM TASK: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ PROJ-123: New Dashboard Charts ││
│ │ ││
│ │ Feature Flag: ││
│ │ Name: dashboard_new_charts_release ││
│ │ Type: Release flag ││
│ │ Created: 2024-01-15 ││
│ │ Owner: @alex ││
│ │ Cleanup due: 2024-02-15 ││
│ │ ││
│ │ Rollout plan: ││
│ │ ☐ 5% - Internal testing ││
│ │ ☐ 20% - Beta customers ││
│ │ ☐ 50% - General availability ││
│ │ ☐ 100% - Full rollout ││
│ │ ☐ Remove flag (cleanup) ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
Rollout Process
FEATURE ROLLOUT STAGES:
┌─────────────────────────────────────────────────────────────┐
│ │
│ STAGE 1: INTERNAL (0%) │
│ ───────────────────── │
│ Flag: OFF by default │
│ Access: Enabled for internal emails only │
│ Purpose: QA and internal testing │
│ Duration: Until confident │
│ │
│ STAGE 2: BETA (5-10%) │
│ ───────────────────── │
│ Flag: Enabled for selected customers │
│ Access: Opt-in beta users │
│ Purpose: Early feedback, bug finding │
│ Duration: 1-2 weeks │
│ Monitor: Error rates, feedback │
│ │
│ STAGE 3: GRADUAL (10% → 50%) │
│ ──────────────────────────── │
│ Flag: Percentage rollout │
│ Access: Random sampling │
│ Purpose: Scale testing │
│ Duration: Days per stage │
│ Monitor: Performance, metrics │
│ │
│ STAGE 4: GENERAL (50% → 100%) │
│ ───────────────────────────── │
│ Flag: Increasing percentage │
│ Access: Remaining users │
│ Purpose: Full rollout │
│ Duration: Days │
│ Monitor: All metrics │
│ │
│ STAGE 5: CLEANUP │
│ ──────────────── │
│ Flag: Remove entirely │
│ Code: Remove flag checks │
│ Purpose: Eliminate tech debt │
│ Timeline: Within 30 days of 100% │
└─────────────────────────────────────────────────────────────┘
Flag Cleanup
Preventing Flag Debt
FEATURE FLAG CLEANUP:
┌─────────────────────────────────────────────────────────────┐
│ │
│ FLAG DEBT PROBLEM: │
│ │
│ Week 1: 5 flags │
│ Month 1: 15 flags │
│ Month 6: 47 flags (half obsolete) │
│ Year 1: 100+ flags, nobody knows which are active │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ CLEANUP RULES: │
│ │
│ 1. SET EXPIRATION AT CREATION │
│ Every release flag has cleanup date │
│ Default: 30 days after 100% rollout │
│ │
│ 2. TRACK IN GITSCRUM │
│ Cleanup task created with feature │
│ Linked to original feature task │
│ Assigned to feature owner │
│ │
│ 3. REGULAR AUDITS │
│ Monthly: Review all flags │
│ Identify: Flags at 100% for > 30 days │
│ Action: Create cleanup tasks │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ CLEANUP TASK: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ TECH-456: Remove dashboard_new_charts flag ││
│ │ ││
│ │ Feature: New Dashboard Charts (PROJ-123) ││
│ │ Flag at 100% since: 2024-02-01 ││
│ │ Cleanup due: 2024-03-01 ││
│ │ ││
│ │ Tasks: ││
│ │ ☐ Remove flag from config ││
│ │ ☐ Remove flag checks from code ││
│ │ ☐ Delete unused code paths ││
│ │ ☐ Update tests ││
│ │ ☐ Deploy ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
Flag Dashboard
Visibility and Tracking
FEATURE FLAG STATUS OVERVIEW:
┌─────────────────────────────────────────────────────────────┐
│ FEATURE FLAGS DASHBOARD │
├─────────────────────────────────────────────────────────────┤
│ │
│ ACTIVE FLAGS: 12 │
│ │
│ BY STATUS: │
│ 🟢 Rolling out: 3 │
│ 🟡 At 100%: 4 (need cleanup) │
│ 🔵 Experiments: 2 │
│ ⚪ Permanent: 3 │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ FLAG ROLLOUT SINCE ACTION │
│ ──────────────────────────── ───────── ─────── ──────── │
│ dashboard_new_charts 100% 14 days Cleanup! │
│ checkout_redesign 50% 3 days Monitor │
│ search_v2 20% 7 days Expand │
│ mobile_nav_experiment 50%/50% 5 days Running │
│ premium_reports perm - - │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ NEEDS ATTENTION: │
│ │
│ ⚠️ dashboard_new_charts at 100% for 14 days │
│ → Create cleanup task │
│ │
│ ⚠️ payment_gateway_v2 at 100% for 45 days │
│ → Overdue for cleanup! │
│ │
│ [View all flags] [Create new flag] [Run audit] │
└─────────────────────────────────────────────────────────────┘
Implementation Patterns
Code Patterns
FEATURE FLAG CODE PATTERNS:
┌─────────────────────────────────────────────────────────────┐
│ │
│ SIMPLE CHECK: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ if (featureFlags.isEnabled('new_dashboard')) { ││
│ │ return <NewDashboard /> ││
│ │ } ││
│ │ return <OldDashboard /> ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ WITH CONTEXT: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ if (featureFlags.isEnabled('premium_feature', { ││
│ │ userId: user.id, ││
│ │ plan: user.plan ││
│ │ })) { ││
│ │ // Show premium feature ││
│ │ } ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ AVOID: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ // ❌ Nested flags ││
│ │ if (flag1 && flag2 && !flag3) { ... } ││
│ │ ││
│ │ // ❌ Flags in loops ││
│ │ items.map(item => ││
│ │ featureFlags.isEnabled('x') ? ... : ... ││
│ │ ) ││
│ │ ││
│ │ // ❌ Late flag check (side effects already happened) ││
│ │ processPayment(); ││
│ │ if (featureFlags.isEnabled('new_receipt')) { ... } ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ BEST PRACTICES: │
│ • Check early in request/component │
│ • Keep flag logic simple │
│ • Cache flag values per request │
│ • Log flag evaluations for debugging │
└─────────────────────────────────────────────────────────────┘