← Back to all articles

Feature Flags in .NET with IFeatureManager

Published

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 Feature Flags Are Useful

  • Temporarily enabling or quickly disabling a feature—for example, during a new release or a hotfix.

  • Disabling problematic functionality during failures.

  • Running A/B tests.

  • Supporting temporary scenarios, such as promotions.

How It Works

Register Feature Management in the dependency injection container and add filters if needed. For example, TimeWindowFilter 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();

Configure Flags in appsettings.json

Set the feature flag 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 with IFeatureManager

Check a flag’s state by injecting IFeatureManager and calling IsEnabledAsync:

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 through configuration without redeploying.

This approach saves time, reduces the risk of release errors, and gives the team more control over functionality directly in production.