Azure App Configuration for .NET: Centralised Settings and Feature Flags

Managing configuration across multiple services, environments, and deployment slots gets messy quickly. Azure App Configuration provides a centralised store for non-secret settings and feature flags, with first-class .NET integration.

Where Key Vault stores secrets, App Configuration stores everything else: feature flags, connection endpoints, UI settings, timeout values, and anything you'd typically put in appsettings.json but want to change without redeploying.

Setting Up the Provider

Install Microsoft.Azure.AppConfiguration.AspNetCore and add it to your host:

Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(
            new Uri("https://my-config.azconfig.io"),
            new DefaultAzureCredential())
        .Select(KeyFilter.Any, LabelFilter.Null)
        .Select(KeyFilter.Any, builder.Environment.EnvironmentName);
});

builder.Services.AddAzureAppConfiguration();

var app = builder.Build();
app.UseAzureAppConfiguration();

The Select calls are important. They load settings in order, with later selections overriding earlier ones. In this example, unlabelled settings are loaded first, then environment-specific settings (e.g., those labelled Production) override them. This gives you a clean layering model.

Labels as Environment Overrides

App Configuration uses labels to distinguish values for different environments. A key like Api:PageSize might have:

Key Label Value
Api:PageSize (none) 25
Api:PageSize Development 5
Api:PageSize Production 50

Your code reads IConfiguration["Api:PageSize"] and gets the right value based on which labels you selected at startup. No conditional logic needed.

Dynamic Refresh

Unlike Key Vault, App Configuration supports efficient change detection using sentinel keys:

Example.cs
builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(
            new Uri("https://my-config.azconfig.io"),
            new DefaultAzureCredential())
        .Select(KeyFilter.Any, LabelFilter.Null)
        .ConfigureRefresh(refresh =>
        {
            refresh.Register("Settings:Sentinel", refreshAll: true)
                .SetRefreshInterval(TimeSpan.FromSeconds(30));
        });
});

The sentinel pattern works like this: change whatever settings you need, then update the sentinel key last. The provider watches only the sentinel key and, when it changes, reloads everything in one go. This avoids partial updates where some settings have changed but others haven't yet.

The UseAzureAppConfiguration() middleware triggers the refresh check on each HTTP request. It's non-blocking — if the refresh interval hasn't elapsed, it returns immediately.

Feature Flags

App Configuration has built-in feature flag support. Define flags in the Azure portal or via CLI, then use them in code:

Example.cs
builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(
            new Uri("https://my-config.azconfig.io"),
            new DefaultAzureCredential())
        .UseFeatureFlags(flagOptions =>
        {
            flagOptions.SetRefreshInterval(TimeSpan.FromMinutes(1));
        });
});

builder.Services.AddFeatureManagement();

Check flags in your services:

Example.cs
public class CheckoutService
{
    private readonly IFeatureManager _featureManager;

    public CheckoutService(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    public async Task<CheckoutResult> ProcessAsync(Cart cart)
    {
        if (await _featureManager.IsEnabledAsync("NewPaymentFlow"))
        {
            return await ProcessWithNewFlowAsync(cart);
        }

        return await ProcessWithLegacyFlowAsync(cart);
    }
}

Or use feature gates on controllers and endpoints:

Example.cs
app.MapGet("/api/v2/orders", async (IOrderService svc) =>
{
    return await svc.GetOrdersV2Async();
})
.WithMetadata(new FeatureGateAttribute("OrdersV2Api"));

Feature flags support filters out of the box — percentage rollouts, time windows, and targeting specific users or groups. These are configured in the portal and evaluated by the Microsoft.FeatureManagement library without any custom code.

Key Vault References

App Configuration can reference Key Vault secrets, combining both stores seamlessly:

Example.cs
options.Connect(
        new Uri("https://my-config.azconfig.io"),
        new DefaultAzureCredential())
    .ConfigureKeyVault(kv =>
    {
        kv.SetCredential(new DefaultAzureCredential());
    });

In App Configuration, set a key's value type to "Key Vault reference" and point it at a secret URI. The configuration provider resolves it transparently. Your code just reads the configuration key as normal.

Practical Tips

App Configuration fills the gap between appsettings.json and Key Vault. It's where your non-secret, runtime-tuneable configuration belongs.