Runtime Feature Toggling in .NET Apps with Azure App Configuration and Managed Identity
Learn how to replace hard-coded feature flags with Azure App Configuration and a managed identity so you can toggle features at runtime without redeploying or storing secrets.
25 Feb 2026, 01:15 UTC

The problem: hard-coded toggles force redeploys
When a feature flag lives in appsettings.json or as an environment variable, changing its state requires rebuilding the container image or redeploying the App Service. This adds latency to experiments, increases the chance of configuration drift, and forces developers to manage secrets if the flag value is sensitive.
Thesis: Azure App Configuration plus managed identity lets you flip flags at runtime without code changes or secrets
By storing flags as key-value pairs in an Azure App Configuration store and authenticating the application with a system-assigned managed identity, you can update a flag in the portal and see the change reflected in the running app within seconds—no rebuild, no secret rotation.
How it works
- Create an App Configuration store and enable the feature-flag schema.
- Add a flag (for example,
beta-feature) as a key-value pair with the content typeapplication/vnd.microsoft.appconfig.ff+json;charset=utf-8. - Enable a system-assigned managed identity on the compute resource (App Service, AKS pod, or VM).
- Grant that identity the
App Configuration Data Readerrole on the store. - Configure the .NET app to read from App Configuration using
IConfigurationRefresherand register the flag for refresh.
When the flag value changes in the portal, the refresher polls the store (default cache expiration is 30 seconds) and updates IConfiguration. The UI or middleware can then read the latest value without restarting the process.
Worked example: .NET 6 web app on Azure App Service
1. Provision the store and identity
Run these commands in Azure Cloud Shell or a local Azure CLI session where you are signed in. Replace placeholders (<your-appconfig-name>, <your-app-service-name>) with your own values. The role assignment step requires Microsoft.Authorization/roleAssignments/write permission (for example, Owner or User Access Administrator on the store).
# Create resource group (if needed)
az group create --name rg-demo --location eastus
# App Configuration store
az appconfig create \
--name <your-appconfig-name> \
--resource-group rg-demo \
--location eastus \
--sku Standard
# Enable system-assigned identity on App Service
az webapp identity assign \
--resource-group rg-demo \
--name <your-app-service-name>
# Get the identity principal ID
IDENTITY_ID=$(az webapp identity show \
--resource-group rg-demo \
--name <your-app-service-name> \
--query principalId -o tsv)
# Assign Data Reader role to the identity
az role assignment create \
--assignee $IDENTITY_ID \
--role "App Configuration Data Reader" \
--scope $(az appconfig show \
--name <your-appconfig-name> \
--resource-group rg-demo \
--query id -o tsv)
2. Add a feature flag
az appconfig kv set \
--name <your-appconfig-name> \
--key "beta-feature" \
--value '{"enabled":true}' \
--content-type "application/vnd.microsoft.appconfig.ff+json;charset=utf-8" \
--resource-group rg-demo
3. Configure the .NET app
In Program.cs (or Startup.cs for older templates):
var builder = WebApplication.CreateBuilder(args);
builder.Configuration
.AddAzureAppConfiguration(options =>
{
options.Connect(new Uri("https://<your-appconfig-name>.azconfig.io"))
// Use managed identity; no secret needed
.UseAzureIdentity(new DefaultAzureCredential())
.Select(KeyFilter.Any, LabelFilter.Null)
// Enable feature-flag refresh
.UseFeatureFlags(featureFlagOptions =>
{
featureFlagOptions.CacheExpirationInterval = TimeSpan.FromSeconds(30);
});
});
var app = builder.Build();
app.MapGet("/beta", (IConfiguration config) =>
{
bool enabled = config.GetValue<bool>("beta-feature:enabled");
return enabled ? "Feature ON" : "Feature OFF";
});
app.Run();
The DefaultAzureCredential automatically picks up the system-assigned managed identity when running in Azure App Service. This example targets .NET 6 with the Microsoft.Azure.AppConfiguration.AspNetCore provider; confirm the current package version and API surface against the official docs before production use.
4. Verify runtime toggling
- Deploy the app (for example, via
az webapp upor your CI/CD pipeline). - Navigate to
https://<your-app-service-name>.azurewebsites.net/beta; you should see "Feature ON". - In the Azure portal, change the flag value to
{"enabled":false}and save. - Refresh the page after up to 30 seconds; the response changes to "Feature OFF" without any redeployment.
To confirm the refresh is working, enable diagnostic settings on the App Configuration store and send logs to Log Analytics. Query the read operations and check that the caller identity matches the managed identity's object ID, which also proves no other principal is reading your configuration.
Trade-off: refresh latency and malformed values
Feature-flag updates are not instantaneous; the default cache expiration is 30 seconds, which may be too slow for low-latency experiments. You can lower the interval, but each refresh incurs a network call and adds overhead to the request that triggers it. Additionally, if the flag's JSON is malformed or the enabled property is missing, the configuration binder can throw; guard against this with a fallback value or a try/catch so a bad flag never takes the app down.
Keep the managed identity scoped to App Configuration Data Reader only. Broader roles such as Contributor would let a compromised app modify or delete configuration for every other consumer of the store.
Actionable next steps
- Start with a single flag in a dev App Configuration store to validate the flow end to end.
- Adjust
CacheExpirationIntervalbased on your tolerance for lag versus request overhead. - Use Azure Monitor to track configuration read latency and alert on sudden spikes that could indicate a misconfigured refresh interval.
- Review the store's diagnostic logs periodically to confirm only the expected managed identity performs data-plane reads.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.