Skip to main content

Command Palette

Search for a command to run...

Update Your Configuration and Secret Without Restarting Your App (ASP.NET Core)

Updated
6 min read
Update Your Configuration and Secret Without Restarting Your App (ASP.NET Core)

In modern cloud-native applications, the ability to update configuration or secret at runtime — without redeploying or restarting — is a huge productivity and operational win. ASP.NET Core has excellent built-in support for this in three common scenarios:

  1. JSON-based configuration files (e.g., appsettings.json)

  2. Secrets stored in Azure Key Vault

  3. Centralized configuration & feature flags in Azure App Configuration

Let’s look at exactly what works, what doesn’t, and the gotchas you need to know.

1. Hot-Reloading JSON Configuration Files (No App Restart Needed)

By default, most ASP.NET Core templates already enable hot reload for appsettings.json — you just have to use the right options pattern.

✅ How It Works Out of the Box

When you create a project with:

C#

var builder = WebApplication.CreateBuilder(args);

The default host builder automatically registers your JSON files with reloadOnChange: true:

C#

builder.Configuration
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);

This sets up a file system watcher. As soon as the file changes on disk, the IConfigurationRoot is refreshed.

✅ How to Read the Latest Values

You have two good options:

InterfaceWhen It UpdatesBest For
IOptionsSnapshot<T>On the next HTTP request (scoped)Web-facing code (controllers, minimal APIs, Razor pages)
IOptionsMonitor<T>Immediately (singleton + change notifications)Background services, hosted services, or any code that needs real-time updates

Example:

C#

public class MyService
{
    private readonly MySettings _settings;

    // Updates immediately when file changes
    public MyService(IOptionsMonitor<MySettings> settings)
    {
        _settings = settings.CurrentValue;

        // Optional: react to future changes
        settings.OnChange(updatedSettings => {
            _settings = updatedSettings;
            // Trigger whatever logic you need
        });
    }
}

❌ What Does NOT Work

ApproachWhy It Fails
IOptions<T>Values are read once at startup and cached
Manually reading IConfiguration once and storing in a singletonYou’re holding a stale snapshot
Hard-coded values or static fieldsObviously never change

Limitations of JSON Hot Reload

Only JSON files added via AddJsonFile(..., reloadOnChange: true) support this. The following sources are static (loaded once at startup):

  • Environment variables

  • Command-line arguments

  • User secrets (in development)

  • Most other providers (Azure App Configuration has its own mechanism, etc.)

2. Hot-Reloading Secrets from Azure Key Vault (Dynamic Refresh)

Storing secrets directly in appsettings.json or user secrets is convenient for development, but in production you usually want them in Azure Key Vault. The good news: you can make those secrets refresh automatically too.

✅ How to Enable Periodic Refresh

C#

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new AzureKeyVaultConfigurationOptions
    {
        ReloadInterval = TimeSpan.FromMinutes(10),   // ← critical line
        Manager = new KeyVaultSecretManager()       // optional: prefix filtering, etc.
    });

The ReloadInterval property is what turns one-time loading into periodic polling.

How the Polling Works

  • Every ReloadInterval, the provider queries Key Vault for the current version of each secret it previously loaded.

  • Azure only transfers the secret value if the version has actually changed.

  • When a new version is detected → the entire configuration root is refreshed → IOptionsMonitor<T> and IOptionsSnapshot<T> pick up the new values exactly like JSON file changes.

Again, use IOptionsMonitor<T> for instant updates (great for background services that read secrets) or IOptionsSnapshot<T> for per-request freshness.

⚠️ Important Operational Considerations

ConsiderationRecommendation
API call volumeEvery reload hits Key Vault for metadata of all secrets you loaded
Quota impactIn production, use a longer interval (20–60 minutes)
CostNegligible unless you have thousands of secrets and very short intervals
Immediate propagationStill limited by your chosen ReloadInterval

❌ What Does NOT Refresh Automatically

ApproachResult
AddAzureKeyVault without ReloadIntervalSecrets loaded once at startup only
Using IOptions<T>Values frozen even if config root reloads
Manually calling KeyVaultClient.GetSecretAsync and cachingYou have to implement your own polling/caching

3. Hot-Reloading Azure App Configuration (The Most Powerful Option)

Azure App Configuration is the go-to service for centralized config, feature flags, and Key Vault references. It supports true dynamic refresh without restarting your app — and it’s smarter than simple polling.

✅ How to Enable It

C#

builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(connectionString)
           // Register keys you want to watch (or use a sentinel pattern)
           .ConfigureRefresh(refresh =>
           {
               // Option 1: Watch a single "sentinel" key (recommended)
               refresh.Register("Sentinel", refreshAll: true)
                      .SetCacheExpiration(TimeSpan.FromMinutes(5));

               // Option 2: Watch individual keys (less efficient)
               // refresh.Register("MyApp:Settings:BackgroundColor", refreshAll: false);
           });

    // Optional: trigger refresh on every request (web apps)
    // options.UseFeatureFlags();
});

For web apps, add the refresh middleware (triggers on each request):

C#

app.UseAzureAppConfiguration();

How the Sentinel Pattern Works (Best Practice)

  1. Create a dummy key in App Configuration called Sentinel (value can be a version number or timestamp).

  2. Your app checks this key periodically (based on cache expiration).

  3. When you need to push a new config:

    • Update all your real keys first.

    • Finally update Sentinel → your app detects the change → reloads everything exactly once.

  4. New values instantly appear via IOptionsMonitor<T> / IOptionsSnapshot<T>.

This avoids polling every single key and gives you atomic, consistent updates.

✅ Same Options Pattern Applies

Use IOptionsMonitor<T> (immediate) or IOptionsSnapshot<T> (per-request) — exactly like JSON and Key Vault.

⚠️ Important Notes

ConsiderationRecommendation
Refresh triggerPrefer sentinel key + longer cache (5–30 min)
Cost & throttlingOnly polls the watched keys (usually just the sentinel)
Feature flagsAutomatically refreshed too (with UseFeatureFlags())
Key Vault referencesRefresh App Config → automatically pulls latest secret version

❌ What Does NOT Refresh

  • Not registering any keys for refresh

  • Forgetting app.UseAzureAppConfiguration() in web apps

  • Using plain IConfiguration.GetValue<T>() without the options pattern

Quick Checklist: “Can I Change This Without a Restart?”

SourceHot Reload Possible?How?
appsettings*.jsonYes (default)reloadOnChange: true + IOptionsMonitor/Snapshot
Environment variablesNoRequires process restart
Command-line argsNoRequires process restart
Azure Key Vault (direct)YesReloadInterval + IOptionsMonitor/Snapshot
Azure App ConfigurationYes (best option)Sentinel key + ConfigureRefresh + middleware
Database-driven configYes (manual)Implement your own polling + IOptionsMonitor
💡
You can find out more about setting up Azure App Configuration and Azure Key Vault properly by reading this article: Azure App Configuration in ASP.NET Core Guide

Final Thoughts

Hot-reloading configuration is one of those small features that has an outsized impact on operations and developer happiness.

  • Most apps get JSON hot reload for free.

  • Add one line for Key Vault polling when you need simple secret rotation.

  • Switch to Azure App Configuration with the sentinel pattern when you want centralized config, feature flags, and atomic zero-downtime updates.

Pick the approach that fits your app — and never restart again just to change a setting or rotate a secret! 🚀