A Practical Guide to ASP.NET Core Configuration Best Practices.

Table of contents

What is application configuration?
In a .NET application, application configuration refers to the process of loading settings—typically key-value pairs—into your application or hosting environment. These settings can come from multiple sources, known as configuration providers.
⚙️ Host and Application Configuration in ASP.NET Core
ASP.NET Core separates configuration into two main categories:
1. Host Configuration
Controls how the application is hosted and started (e.g., server URLs, environment).
Loaded early—before the app is built.
Examples:
ASPNETCORE_ENVIRONMENT
– sets the environment (e.g., Development, Production)DOTNET_URLS
– sets the URLs the app will listen on
2. Application Configuration
Governs application behavior and feature settings used at runtime.
Loaded after the host is built.
Examples:
ConnectionStrings:Default
– database connection stringJwtSettings:Secret
– authentication secretMyCustomFeature:Enabled
– feature flags
Both types of configuration are layered from multiple sources (JSON files, env vars, CLI args, etc.), but their timing and purpose differ.
ASPNETCORE_ENVIRONMENT
or DOTNET_ENVIRONMENT
variable to the desired environment (e.g., Development
, Staging
, Production
). This determines which appsettings.{Environment}.json
file will be used at runtime.Configuration priority.
Even though host configuration is loaded first and used to build the application host, application configuration has higher effective priority at runtime.
🔑 Here's how ASP.NET Core resolves conflicts when the same key exists in multiple sources:
Priority | Source | Type |
1️⃣ | Command-line arguments | App + Host |
2️⃣ | Environment variables (no prefix) | Application |
3️⃣ | User secrets (Development only) | Application |
4️⃣ | appsettings.{Environment}.json | Application |
5️⃣ | appsettings.json | Application |
6️⃣ | DOTNET_ , ASPNETCORE_ environment variables | Host only |
✅ In short: application configuration overrides host configuration during runtime. This means your feature flags, secrets, and connection strings won’t be unintentionally overridden by host-level settings.
🏗️ WebApplicationBuilder in ASP.NET Core Application.
When you initialize an ASP.NET Core application, you'll commonly see the following line of code:
var builder = WebApplication.CreateBuilder(args);
This single line does a lot under the hood. One of its key responsibilities is setting up a default configuration system with a built-in order of precedence. Here's how configuration sources are loaded—from lowest to highest priority:
appsettings.json
appsettings.{Environment}.json
(e.g.,appsettings.Development.json
)User secrets (only in the
Development
environment)Environment variables
Command-line arguments
Internally, this is roughly equivalent to the following:
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
if (env.IsDevelopment())
{
config.AddUserSecrets<Program>();
}
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
});
This layered configuration model gives you flexibility to manage settings in a way that’s appropriate for different environments and deployment scenarios.
🦀 Common Mistake: Re-adding Configuration Sources
A common pitfall in ASP.NET Core is manually re-adding configuration providers after this line:
var builder = WebApplication.CreateBuilder(args);
For example:
builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
At first glance, this might seem harmless—but it's usually unnecessary and potentially harmful.
optional: false
, changing file paths, or customizing the order). Leverage the default configuration setup and only extend it when necessary.By manually adding configuration files again, you risk:
Overriding existing values unintentionally
Redundant file reads
Unexpected configuration merge behavior.
🤝 Understanding Merged Configuration
The configuration system in ASP.NET Core merges settings from all providers. If multiple sources define values for the same key, the last one added wins.
🔹 Adding New Keys
Suppose you have the following in your appsettings.json
:
"JwtSetting": {
"Issuer": "yourIssuer",
"Audience": "yourAudience",
"AccessTokenExpMinute": 10,
"RefreshTokenExpiration": 30
}
And you define this in your user secrets (Development only):
"JwtSetting": {
"Secret": "your-secret-key"
}
The final merged configuration at runtime will be:
"JwtSetting": {
"Issuer": "yourIssuer",
"Audience": "yourAudience",
"AccessTokenExpMinute": 10,
"RefreshTokenExpiration": 30,
"Secret": "your-secret-key"
}
Each source contributes to the overall object unless a full override is performed.
🔹 Overriding Existing Keys
If the same key is defined in multiple places, the source added last takes precedence. For example:
// appsettings.json
"ApiKey": "ValueFromAppSettings"
// appsettings.Development.json
"ApiKey": "ValueFromDevSettings"
Then you set an environment variable:
set ApiKey=ValueFromEnv
And run the application with a command-line override:
dotnet run --ApiKey=ValueFromCommandLine
The final value of ApiKey
will be:
"ApiKey": "ValueFromCommandLine"
Custom Configuration Sources
In addition to the built-in configuration providers, ASP.NET Core makes it easy to add custom configuration sources. This is especially useful for keeping sensitive data like secrets or credentials out of your codebase.
For example, instead of storing everything in appsettings.json
you could store some settings in the Azure App Configuration or securely store secrets in the Azure Key Vault.
🔗 I’ve written a detailed guide on integrating Azure Key Vault with ASP.NET Core. You can read it here: Azure Key Vault: Secure .NET App Secrets
Conclusion
Using configuration properly in ASP.NET Core enables your application to be environment-aware, secure, and maintainable. By understanding how the configuration system merges values across sources—and by using the right source for the right purpose—you can avoid common pitfalls and keep your app flexible for development, testing, and production.
For best results:
Let
WebApplication.CreateBuilder
handle the default setup.Use additional providers (like Azure Key Vault or custom JSON files) only when necessary.
Understand and leverage the configuration precedence order to avoid surprises at runtime.
Subscribe to my newsletter
Read articles from Kristiadhy directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Kristiadhy
Kristiadhy
Experienced Full Stack .NET developer with a proven track record of designing and implementing robust business applications. Proficient in using ASP.NET Core Web API, Blazor, and WinForms to deliver high-quality, efficient code and scalable solutions. Strong focus on implementing industry best practices for cleaner and scalable outcomes.