Deploying new features is risky - bugs can affect all users instantly. Feature flags let you deploy code to production but control who sees new features. You can gradually roll out to 1%, then 10%, then 100% of users, and instantly disable a feature if something goes wrong - no redeployment needed.
Feature flags enable trunk-based development, where all developers commit to main and features are hidden behind flags until ready.
// Program.csvar builder = WebApplication.CreateBuilder(args);builder.Services.AddFeatureManagement();var app = builder.Build();
// appsettings.json{"FeatureManagement": {"NewDashboard": true,"BetaFeatures": false,"ExperimentalSearch": {"EnabledFor": [{"Name": "Percentage","Parameters": {"Value": 10}}]}}}
✅ Figure: Good example - Configure feature flags in appsettings.json
// Bad - code is always executed, no way to disablepublic async Task<IActionResult> GetDashboard(){var data = await _newDashboardService.GetData(); // New untested codereturn Ok(data);}
❌ Figure: Bad example - No way to disable new code if issues arise
// Good - feature can be toggled without redeploymentpublic async Task<IActionResult> GetDashboard(IFeatureManager featureManager){if (await featureManager.IsEnabledAsync("NewDashboard")){var data = await _newDashboardService.GetData();return Ok(data);}// Fallback to old dashboardvar legacyData = await _legacyDashboardService.GetData();return Ok(legacyData);}
✅ Figure: Good example - Feature can be disabled instantly if problems occur
<feature name="NewDashboard"><NewDashboardComponent /></feature><feature name="NewDashboard" negate="true"><LegacyDashboardComponent /></feature>
✅ Figure: Good example - Use feature tag helper in views
Roll out to a percentage of users to catch issues before they affect everyone:
{"FeatureManagement": {"NewCheckout": {"EnabledFor": [{"Name": "Percentage","Parameters": {"Value": 5}}]}}}
✅ Figure: Good example - Roll out to 5% of users first, increase gradually
Enable features for specific users or groups:
{"FeatureManagement": {"BetaFeatures": {"EnabledFor": [{"Name": "Targeting","Parameters": {"Audience": {"Groups": ["BetaTesters", "InternalUsers"],"DefaultRolloutPercentage": 0}}}]}}}
✅ Figure: Good example - Enable beta features only for specific users or groups
During incidents, disable expensive or problematic features instantly:
app.MapGet("/api/recommendations", async (IFeatureManager featureManager,IRecommendationService recommendations) =>{// Kill switch - disable expensive ML recommendations during high loadif (!await featureManager.IsEnabledAsync("MLRecommendations")){return Results.Ok(new { items = Array.Empty<object>(), source = "disabled" });}var items = await recommendations.GetPersonalizedAsync();return Results.Ok(new { items, source = "ml" });});
✅ Figure: Good example - Disable expensive features during incidents without redeployment
| Use Feature Flags | Use Configuration |
| New features being developed | Stable settings (connection strings, URLs) |
| Gradual rollouts needed | Per-environment differences |
| Quick enable/disable required | Rarely changed values |
| A/B testing | Infrastructure settings |
NewCheckoutFlow not Flag1