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:
JSON-based configuration files (e.g., appsettings.json)
Secrets stored in Azure Key Vault
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:
| Interface | When It Updates | Best 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
| Approach | Why It Fails |
| IOptions<T> | Values are read once at startup and cached |
| Manually reading IConfiguration once and storing in a singleton | You’re holding a stale snapshot |
| Hard-coded values or static fields | Obviously 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.
✅ Recommended Options Pattern.
Again, use IOptionsMonitor<T> for instant updates (great for background services that read secrets) or IOptionsSnapshot<T> for per-request freshness.
⚠️ Important Operational Considerations
| Consideration | Recommendation |
| API call volume | Every reload hits Key Vault for metadata of all secrets you loaded |
| Quota impact | In production, use a longer interval (20–60 minutes) |
| Cost | Negligible unless you have thousands of secrets and very short intervals |
| Immediate propagation | Still limited by your chosen ReloadInterval |
❌ What Does NOT Refresh Automatically
| Approach | Result |
| AddAzureKeyVault without ReloadInterval | Secrets loaded once at startup only |
| Using IOptions<T> | Values frozen even if config root reloads |
| Manually calling KeyVaultClient.GetSecretAsync and caching | You 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)
Create a dummy key in App Configuration called Sentinel (value can be a version number or timestamp).
Your app checks this key periodically (based on cache expiration).
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.
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
| Consideration | Recommendation |
| Refresh trigger | Prefer sentinel key + longer cache (5–30 min) |
| Cost & throttling | Only polls the watched keys (usually just the sentinel) |
| Feature flags | Automatically refreshed too (with UseFeatureFlags()) |
| Key Vault references | Refresh 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?”
| Source | Hot Reload Possible? | How? |
| appsettings*.json | Yes (default) | reloadOnChange: true + IOptionsMonitor/Snapshot |
| Environment variables | No | Requires process restart |
| Command-line args | No | Requires process restart |
| Azure Key Vault (direct) | Yes | ReloadInterval + IOptionsMonitor/Snapshot |
| Azure App Configuration | Yes (best option) | Sentinel key + ConfigureRefresh + middleware |
| Database-driven config | Yes (manual) | Implement your own polling + IOptionsMonitor |
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! 🚀



