Feature flags in .NET with IFeatureManager
2 min readAug 14, 2025
Press enter or click to view image in full size![]()
IFeatureManager from the Microsoft.FeatureManagement package manages feature flags in .NET.
It lets you choose the right branch of logic while the application is running.
Where it’s useful:
- temporary enablement or quick disabling of a feature — for example, during a new release or a hotfix
- disabling problematic functionality during failures
- A/B testing
- temporary scenarios, such as promotions
How it works:
Register Feature Management in DI, Add filters if needed. For example, TimeWindow activates a flag only within a specific time range
using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureFilters;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFeatureManagement()
// If you need a time window filter, add the following line
.AddFeatureFilter<TimeWindowFilter>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = "Feature Flags Demo API", Version = "v1" });
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapControllers();
app.Run();Set values in appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"FeatureManagement": {
"NewDashboard": true,
"HolidayPromo": {
"EnabledFor": [
{
"Name": "TimeWindow",
"Parameters": {
"Start": "2024-12-01T00:00:00Z",
"End": "2025-12-31T23:59:59Z"
}
}
]
}
}
}Check a flag’s state through IFeatureManager
using Microsoft.AspNetCore.Mvc;
using Microsoft.FeatureManagement;
namespace FeatureFlagsDemo.Api.Controllers;
[ApiController]
[Route("api/[controller]")]
public class DashboardController(IFeatureManager featureManager) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetDashboard()
{
var useNewDashboard = await featureManager.IsEnabledAsync("NewDashboard");
if (useNewDashboard)
{
return Ok(new
{
Version = "New",
Data = GetNewDashboardData(),
});
}
return Ok(new
{
Version = "Legacy",
Data = GetLegacyDashboardData(),
});
}
[HttpGet("promo")]
public async Task<IActionResult> GetHolidayPromo()
{
if (!await featureManager.IsEnabledAsync("HolidayPromo"))
{
return Ok(new { Message = "No active promotions" });
}
return Ok(new
{
Message = "Holiday Special Offer!",
Discount = "50% OFF",
ValidUntil = "December 31, 2025",
PromoCode = "HOLIDAY2025"
});
}
private static object GetNewDashboardData() => new
{
Charts = new[]
{
new { Name = "Revenue Chart", Type = "Line", Interactive = true },
new { Name = "User Activity", Type = "Heatmap", Interactive = true },
new { Name = "Performance Metrics", Type = "Gauge", Interactive = true }
},
Layout = "Modern Grid",
Theme = "Dark Mode Available",
Features = new[] { "Real-time Updates", "Custom Widgets", "Export Options" }
};
private static object GetLegacyDashboardData() => new
{
Charts = new[]
{
new { Name = "Basic Revenue", Type = "Bar", Interactive = false },
new { Name = "Simple Stats", Type = "Table", Interactive = false }
},
Layout = "Classic List",
Theme = "Light Only",
Features = new[] { "Static Reports" }
};
}As a result, you can change application behavior via configuration, without redeploying.
This approach saves time, reduces the risk of release errors, and gives the team more control over functionality directly in production.
