Sitemap

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.

--

--

Responses (1)