🔥 Pragmatic .NET Code Rules Course is on Presale - 40% off!BUY NOW

Feature Flags without redeploying: what people usually get wrong in .NET

December 23 2025

This issue is made possible thanks to JetBrains, who help keep this newsletter free for everyone. A huge shout-out to them for their support of our community. Let's thank them by entering the link below. Struggling with slow builds, tricky bugs, or hard-to-understand performance issues? dotUltimate fixes all of that. It’s the all-in-one toolbox for serious .NET developers. 👉 Upgrade your .NET workflow.

Introduction

How do you enable or disable features without redeploying the app?

If your first thought is “I’ll just flip a value in appsettings.json” - you’re not alone. But that’s also where most Feature Flag implementations quietly fail.

In the last few days, I shared a short post about Feature Flags in .NET, and the comments were exciting.

They all circled the same confusion:

Do we really avoid redeployment? How does this work with multiple instances? Is appsettings.json enough? Do I still need to run a DevOps release?

Let’s clear this up - with real code that actually works.

First: What “Without Redeploying” Actually Means

Let’s be very explicit.

“Without redeploying” means:

❌ no build ❌ no release pipeline ❌ no app restart ❌ no new container image ✅ behavior changes while the app is running

If changing a feature flag requires you to click 'Deploy', then you haven’t decoupled deployment from release - you've just moved the toggle.

Why appsettings.json Is NOT Enough

Yes, you can define feature flags in appsettings.json.

C#
{ "FeatureManagement": { "BetaFeature": true }}

But here’s the problem:

  1. appsettings.json is read at startup
  2. each instance has its own copy
  3. any change requires: • file change • restart • redeploy So this works for: • local development • demos • small experiments

But it does not work for: • multiple instances • Kubernetes • Azure App Service • real production traffic

To truly avoid redeployment, feature flags must live outside the application.

The Correct Architecture

Feature Flags must be: • centrally stored • shared across instances • read at runtime • refreshable without a restart In .NET, this is exactly what Azure App Configuration + Feature Management gives us. Let’s build this properly.

Step 1: Install Required Packages

These give us: • Feature Flags API • Azure App Configuration integration • runtime refresh support

C#
dotnet add package Microsoft.FeatureManagement.AspNetCoredotnet add package Microsoft.Azure.AppConfiguration.AspNetCore

Step 2: Configure Azure App Configuration

In Azure Portal:

  1. Create Azure App Configuration
  2. Go to Feature Manager
  3. Create a feature flag: • Name: BetaFeature • Enabled: false You now have a central switch. Read the full tutorial about Feature Manager Azure App Configuration.

Step 3: Add Connection String

In appsettings.json:

C#
{ "AzureAppConfig": { "ConnectionString": "<YOUR_CONNECTION_STRING>" }}

In real projects, this belongs in Key Vault or environment variables.

Step 4: Configure Program.cs

This is the part most examples skip or oversimplify.

C#
using Microsoft.FeatureManagement;using Microsoft.Extensions.Configuration.AzureAppConfiguration; var builder = WebApplication.CreateBuilder(args); // 1. Connect to Azure App Configurationbuilder.Host.ConfigureAppConfiguration(config =>{ var settings = config.Build(); config.AddAzureAppConfiguration(options => { options .Connect(settings["AzureAppConfig:ConnectionString"]) // Register feature flags .UseFeatureFlags(featureOptions => { featureOptions.CacheExpirationInterval = TimeSpan.FromSeconds(10); }) // Register refresh with a sentinel key .ConfigureRefresh(refresh => { refresh .Register("FeatureFlags:Sentinel", true) .SetCacheExpiration( TimeSpan.FromSeconds(10)); }); });}); // 2. Add Feature Managementbuilder.Services.AddFeatureManagement(); // 3. Add Azure App Config refresh middlewarebuilder.Services.AddAzureAppConfiguration(); var app = builder.Build(); // Enable refresh middlewareapp.UseAzureAppConfiguration(); app.MapGet("/", () => "Feature Flags Demo is running"); // Feature-gated endpointapp.MapGet("/beta", async (IFeatureManager featureManager) =>{ if (await featureManager.IsEnabledAsync("BetaFeature")) { return Results.Ok("Beta feature is ENABLED"); }  return Results.Ok("Beta feature is DISABLED");}); app.Run();

In Azure App Configuration:

Create a key-value pair: • Key: FeatureFlags:Sentinel • Value: any string (e.g. timestamp)

Whenever you update this value: • all feature flags refresh • no restart • no redeploy

Step 6: See It in Action

Run the app and call GET /beta → ❌ disabled Enable BetaFeature in the Azure Portal Wait ~10 seconds Call /beta again → 🚀 enabled

No redeploy. No restart. No pipeline.

Important Production Gotcha: Caching

Azure App Configuration does cache values.

If you don’t configure refresh: • changes may take minutes • developers think “it doesn’t work”

That’s why: • CacheExpirationInterval • sentinel keys • refresh middleware

matter a lot.

This is where most “Feature Flags don’t work” stories come from.

What About Multiple Instances?

This setup works perfectly with: • multiple app instances • load balancers • Kubernetes • App Service scaling Because: • flags are centralized • decision logic is deterministic • instances are stateless The feature decision does not depend on the instance.

3rd-Party Feature Flag Providers

Azure App Configuration is great if you’re already on Azure.

Other solid options: • LaunchDarkly - enterprise-grade • Unleash - open-source & self-hosted • Flagsmith - SaaS or self-hosted

The provider matters less than the runtime architecture.

When Feature Flags Become a Problem

Feature Flags are powerful - but dangerous if abused: • flags that live for years • nested if statements everywhere • “temporary” flags that never die Best practice: • flags should have an owner • flags should have a removal date • flags should not replace versioning

Wrapping Up

Feature Flags are not about hiding code paths.

hey are about decoupling deployment from release.

If flipping a flag requires a redeploy, you didn’t gain flexibility - you added complexity.

If you want a deeper dive, I’ve already written a full article on Feature Flags in .NET with Azure Feature Management here.

More real-world .NET architecture topics coming soon 🚀 That's all from me for today.


Want to enforce clean code automatically? My Pragmatic .NET Code Rules course shows you how to set up analyzers, CI quality gates, and architecture tests - a production-ready system that keeps your codebase clean without manual reviews. Or grab the free Starter Kit to try it out.

About the Author

Stefan Djokic is a Microsoft MVP and senior .NET engineer with extensive experience designing enterprise-grade systems and teaching architectural best practices.

There are 3 ways I can help you:

1. Pragmatic .NET Code Rules Course

Stop arguing about code style. In this course you get a production-proven setup with analyzers, CI quality gates, and architecture tests — the exact system I use in real projects. Join here.

Not sure yet? Grab the free Starter Kit — a drop-in setup with the essentials from Module 01.

2. Design Patterns Ebooks

Design Patterns that Deliver — Solve real problems with 5 battle-tested patterns (Builder, Decorator, Strategy, Adapter, Mediator) using practical, real-world examples. Trusted by 650+ developers.

Just getting started? Design Patterns Simplified covers 10 essential patterns in a beginner-friendly, 30-page guide for just $9.95.

3. Join 20,000+ subscribers

Every Monday morning, I share 1 actionable tip on C#, .NET & Architecture that you can use right away. Join here.

Join 20,000+ subscribers who mass-improve their .NET skills with actionable tips on C#, Architecture & Best Practices.

Subscribe to
TheCodeMan.net

Subscribe to the TheCodeMan.net and be among the 20,000+ subscribers gaining practical tips and resources to enhance your .NET expertise.