Configuration Options for ASP.NET Core Applications: Provider Pipeline and Patterns
ASP.NET Core applications configure settings through a hierarchical pipeline of providers—including JSON files, environment variables, command-line arguments, and user secrets—that merge into an IConfiguration object supporting reload-on-change and POCO binding.
The dotnet/aspnetcore repository implements a flexible configuration system built on Microsoft.Extensions.Configuration abstractions. Understanding the available configuration options for ASP.NET Core applications allows developers to externalize settings per environment without code changes, leveraging providers that automatically reload or bind to strongly-typed objects.
Built-in Configuration Providers
The configuration pipeline is constructed by IHostBuilder or WebApplicationBuilder (in minimal-API projects) through a series of configuration providers. Each provider implements IConfigurationProvider and supplies key-value pairs that the ConfigurationRoot merges into a single hierarchical view.
JSON File Provider
The most common source for settings is appsettings.json combined with environment-specific variants. In Program.cs, the builder adds these via AddJsonFile:
builder.Configuration
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json",
optional: true, reloadOnChange: true);
When reloadOnChange is set to true, the framework uses file watchers to trigger configuration updates without restarting the application.
Environment Variables Provider
Operating-system environment variables are loaded via AddEnvironmentVariables():
builder.Configuration.AddEnvironmentVariables();
This provider captures variables such as ASPNETCORE_URLS and maps them to configuration keys. Because environment variables are static snapshots, they do not support reload-on-change.
Command-Line Arguments Provider
Arguments passed to dotnet run are bound to keys using the AddCommandLine method:
builder.Configuration.AddCommandLine(args);
Syntax such as --urls https://localhost:5001 overrides earlier provider values.
User Secrets Provider
During development, sensitive data is stored outside the repository in secrets.json. The AddUserSecrets<T>() extension (which relies on ReadableJsonConfigurationSource in src/Tools/dotnet-user-secrets/src/Internal/ReadableJsonConfigurationSource.cs) loads these values:
if (builder.Environment.IsDevelopment())
{
builder.Configuration.AddUserSecrets<Program>();
}
Key-per-File Provider
Containerized deployments often mount secrets as individual files. The KeyPerFileConfigurationProvider (implemented in src/Configuration/KeyPerFile/src/KeyPerFileConfigurationProvider.cs) treats each filename as a key and the file content as the value:
builder.Configuration.AddKeyPerFile("/etc/config", optional: true);
When file watchers are enabled, this provider supports reload-on-change, making it ideal for Kubernetes secrets.
In-Memory Collection
For programmatic defaults or testing, use AddInMemoryCollection:
builder.Configuration.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Key", "Value")
});
Configuration Precedence and Overrides
Providers are registered in a specific order, and the ConfigurationRoot merges them such that later providers override earlier ones. The typical registration order is:
- JSON files (base then environment-specific)
- User secrets (Development only)
- Environment variables
- Command-line arguments
This precedence model allows production deployments to override development settings via environment variables or command-line switches without modifying code.
Hierarchical Keys and Options Binding
Configuration keys use a colon (:) separator to express hierarchy (e.g., Logging:LogLevel:Default). The framework can bind sections directly to POCO classes using the Options pattern:
public class MyOptions
{
public string ConnectionString { get; set; } = default!;
public int MaxItems { get; set; }
}
// In Program.cs
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("MyOptions"));
Alternatively, access values directly via IConfiguration:
public class HomeController : Controller
{
private readonly IConfiguration _config;
public HomeController(IConfiguration config) => _config = config;
public IActionResult Index()
{
var maxItems = _config.GetValue<int>("MyOptions:MaxItems");
return Content($"Max items = {maxItems}");
}
}
The binding process respects data-type conversion, collections, and nested objects automatically.
Reload on Change
Providers that support change notifications (JSON files and Key-per-File) emit an IChangeToken. When reloadOnChange is enabled, the configuration root rebuilds its snapshot, and services consuming IOptionsSnapshot<T> or IConfiguration receive updated values immediately. Static providers such as environment variables and command-line arguments do not support this behavior.
Server-Specific Configuration (Kestrel)
Server-level settings for Kestrel are also expressed through the configuration system. The KestrelServerOptions.Configure(IConfiguration) extension reads the Kestrel section from the merged configuration. The loader in src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs uses a dedicated ConfigurationReader to parse endpoints and certificates:
{
"Kestrel": {
"Endpoints": {
"Http": { "Url": "http://0.0.0.0:5000" },
"Https": {
"Url": "https://0.0.0.0:5001",
"Certificate": {
"Path": "cert.pfx",
"Password": "secret"
}
}
}
}
}
This allows operators to define URLs and TLS certificates via JSON, environment variables, or command-line arguments without touching code.
Summary
- ASP.NET Core builds configuration from a chain of providers registered on
WebApplicationBuilderorIHostBuilder. - Built-in providers include JSON files, environment variables, command-line arguments, user secrets, and key-per-file (for container secrets).
- Precedence is determined by registration order; later providers override earlier values.
- Hierarchical keys use colons and bind to POCOs via
services.Configure<T>()orIConfiguration.GetValue<T>(). - Reload-on-change is supported by JSON and Key-per-File providers, enabling runtime updates without restarts.
- Kestrel settings are loaded from the
Kestrelconfiguration section viaKestrelConfigurationLoader.
Frequently Asked Questions
What is the default configuration order in ASP.NET Core?
The default order is JSON files (appsettings.json then environment-specific), user secrets (Development only), environment variables, and finally command-line arguments. This sequence ensures that command-line arguments override environment variables, which override file-based settings.
How do I reload configuration automatically when appsettings.json changes?
Pass reloadOnChange: true to AddJsonFile. The framework monitors the file for modifications and updates the IConfiguration snapshot automatically. Services using IOptionsSnapshot<T> will receive the new values on the next request.
Can I store secrets securely in ASP.NET Core?
Yes. Use the User Secrets provider (AddUserSecrets<Program>()) during development to keep sensitive data out of source control. For production, use environment variables, Azure Key Vault (via a custom provider), or container secret mounts with the Key-per-File provider.
How do I access nested configuration values in a controller?
Inject IConfiguration into the controller constructor and use the colon-separated key path, or bind a section to a POCO using services.Configure<MyOptions>(Configuration.GetSection("SectionName")) and inject IOptions<MyOptions>.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →