Skip to main content

Command Palette

Search for a command to run...

ASP.NET Core Configuration Guide

Updated
7 min read

ASP.NET Core Configuration Guide

Overview

ASP.NET Core uses a layered configuration system where later sources override earlier ones for the same key.


Configuration Priority Order

Priority Source When Loaded
1 (lowest) appsettings.json Always
2 appsettings.{Environment}.json Always
3 User Secrets Development only
4 Environment variables Always
5 Command-line arguments Always
6 (highest) Azure Key Vault (if registered) When explicitly added in code

Rule: Later sources override earlier ones for the same key.


Environment Detection

ASP.NET Core determines the current environment from the ASPNETCORE_ENVIRONMENT variable.

Common values:

  • Development
  • Staging
  • Production

This is typically set in launchSettings.json for local development:

{
    "profiles": {
        "Dev": {
            "commandName": "Project",
            "environmentVariables": {
                "ASPNETCORE_ENVIRONMENT": "Development"
            },
            "applicationUrl": "http://localhost:5056"
        },
        "Production": {
            "commandName": "Project",
            "environmentVariables": {
                "ASPNETCORE_ENVIRONMENT": "Production"
            },
            "applicationUrl": "http://localhost:5055"
        }
    }
}

Checking environment in code

// During host building 
if (builder.Environment.IsDevelopment()) 
{ 
  // development-only setup 
}
// After app is built 
if (app.Environment.IsProduction()) 
{ 
   // production-only setup 
}

1. appsettings.json Files

Base configuration (always loaded)

appsettings.json

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
        }
    },
    "AllowedHosts": "*"
}

Environment-specific overrides

appsettings.Development.json

{
    "Logging": {
        "LogLevel": {
            "Default": "Debug"
        }
    },
    "ConnectionStrings": {
        "MyDiaryDb": "Server=127.0.0.1;Port=5432;Database=MyDiaryDb_Dev;UserId=postgres;Password=12345;"
    }
}

appsettings.Production.json

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    }
}

How it merges

When running in Development:

appsettings.json → LogLevel: Default = "Information" appsettings.Development.json → LogLevel:Default = "Debug" ← wins

The environment-specific file overrides matching keys, but non-overlapping keys from appsettings.json are still available.


2. User Secrets

What are they?

A development-only mechanism for storing sensitive config values (passwords, API keys) outside the project directory so they are never committed to source control.

Where are they stored?

OS Path
Windows %APPDATA%\Microsoft\UserSecrets\<UserSecretsId>\secrets.json
Linux/Mac ~/.microsoft/usersecrets/<UserSecretsId>/secrets.json

Setup

1. Initialize (one-time per project)

dotnet user-secrets init

This adds a <UserSecretsId> to your .csproj:

<PropertyGroup>
	<TargetFramework>net10.0</TargetFramework>
	<UserSecretsId>a1b2c3d4-e5f6-7890-abcd-ef1234567890</UserSecretsId>
</PropertyGroup>

2. Set secrets

dotnet user-secrets set "ConnectionStrings:MyDiaryDb" "Server=127.0.0.1;Port=5432;Database=MyDiaryDb_Dev;User Id=postgres;Password=SecretPassword;"

3. List secrets

dotnet user-secrets list

4. Remove a secret

dotnet user-secrets remove "ConnectionStrings:MyDiaryDb"

5. Clear all secrets

dotnet user-secrets clear

How they are loaded

You do not need to register them manually. WebApplication.CreateBuilder(args) automatically loads User Secrets when ASPNETCORE_ENVIRONMENT=Development:

This happens internally — you don't write this yourself:

if (builder.Environment.IsDevelopment()) { builder.Configuration.AddUserSecrets(); }

Priority

User Secrets override appsettings.Development.json for the same key:

appsettings.json → ConnectionStrings:MyDiaryDb = (not set) appsettings.Development.json → ConnectionStrings:MyDiaryDb = "local-dev-string" User Secrets → ConnectionStrings:MyDiaryDb = "secret-string" ← wins

Key characteristics

Question Answer
In source control? No
Works in Production? No, Development only
Overrides appsettings.Development.json? Yes
Needs manual registration? No, automatic in Development
Shared across team? No, per-developer

When to use

  • Local database passwords
  • API keys for third-party services during development
  • Any secret you don't want in Git

3. Environment Variables

How they work

Environment variables override all file-based config. Use __ (double underscore) as a section separator:

Linux/Mac

export ConnectionStrings__MyDiaryDb="Server=prod-server;..."

Windows (PowerShell)

$env:ConnectionStrings__MyDiaryDb = "Server=prod-server;..."

In code

// Read normally — the framework resolves the source automatically var connectionString = builder.Configuration.GetConnectionString("MyDiaryDb");

Priority

Environment variables override User Secrets and appsettings files:

appsettings.Development.json → ConnectionStrings:MyDiaryDb = "dev-string" User Secrets → ConnectionStrings:MyDiaryDb = "secret-string" Environment Variable → ConnectionStrings:MyDiaryDb = "env-string" ← wins

Common use cases

  • CI/CD pipelines
  • Docker containers
  • Azure App Service (Application Settings)

4. Azure Key Vault

What it does

Stores secrets centrally in Azure. Your app fetches them at startup and they become part of the configuration system.

Setup

Install package

dotnet add package Azure.Identity dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets

Register in Program.cs (conditionally)

using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
// Only connect to Key Vault in non-Development environments 
if (!builder.Environment.IsDevelopment()) 
{ 
  var keyVaultUrl = new Uri("https://your-vault-name.vault.azure.net/"); 
  builder.Configuration.AddAzureKeyVault(keyVaultUrl, new DefaultAzureCredential()); 
}
// Connection string is resolved from whatever source is available 
builder.Services.AddDbContext<DataContext>(options => { 
  options.UseNpgsql(builder.Configuration.GetConnectionString("MyDiaryDb")); 
});

Secret naming in Key Vault

Use -- as separator (Key Vault doesn't allow :):

Key Vault Secret Name Maps to Configuration Key
ConnectionStrings--MyDiaryDb ConnectionStrings:MyDiaryDb
Jwt--Key Jwt:Key
Jwt--Issuer Jwt:Issuer

Priority

Key Vault is the highest priority when registered (added last):

appsettings.json → ConnectionStrings:MyDiaryDb = (not set) appsettings.Production.json → ConnectionStrings:MyDiaryDb = (not set) Environment Variables → ConnectionStrings:MyDiaryDb = "env-string" Azure Key Vault → ConnectionStrings:MyDiaryDb = "vault-string" ← wins

Authentication methods (DefaultAzureCredential)

DefaultAzureCredential tries these in order:

  1. Environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET)
  2. Managed Identity (Azure App Service, VM, Container Apps)
  3. Visual Studio credentials
  4. Azure CLI (az login)
  5. Azure PowerShell

Why wrap in environment check

// BAD — tries to connect to Azure even in Development 
var keyVaultUrl = new Uri("https://your-vault.vault.azure.net/"); 
builder.Configuration.AddAzureKeyVault(keyVaultUrl, new DefaultAzureCredential());

// GOOD — only connects in Production 
if (!builder.Environment.IsDevelopment()) 
{ 
  var keyVaultUrl = new Uri("https://your-vault.vault.azure.net/"); 
  builder.Configuration.AddAzureKeyVault(keyVaultUrl, new DefaultAzureCredential()); 
}

Without the check, AddAzureKeyVault attempts to authenticate to Azure immediately at startup. If credentials are not available locally, the app crashes or hangs before it ever reads your local config files.


5. Command-Line Arguments

Highest priority among built-in sources (before Key Vault):

dotnet run --ConnectionStrings:MyDiaryDb="Server=override;..."

Useful for one-off overrides during testing.


Complete Example: Program.cs

using Azure.Identity; using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Configuration is already loaded in this order: 
  // 1. appsettings.json 
  // 2. appsettings.{Environment}.json 
  // 3. User Secrets (Development only, automatic) 
  // 4. Environment variables 
  // 5. Command-line args
  // 6. Azure Key Vault (Production only, manual) 
  if (!builder.Environment.IsDevelopment()) 
  { 
    var keyVaultUrl = new Uri("https://your-vault.vault.azure.net/"); 
    builder.Configuration.AddAzureKeyVault(keyVaultUrl, new DefaultAzureCredential()); 
  }
// This resolves from whichever source has the highest priority 
  var connectionString = builder.Configuration.GetConnectionString("MyDiaryDb");
  builder.Services.AddDbContext<DataContext>(options => { options.UseNpgsql(connectionString); });
  var app = builder.Build(); app.Run();

Summary: Which source to use when

Environment Recommended secret source
Local Development User Secrets
CI/CD Pipeline Environment variables
Azure App Service Azure Key Vault or App Settings
Docker/Container Environment variables

Quick Reference: Common Commands

Initialize user secrets

dotnet user-secrets init

Set a secret

dotnet user-secrets set "ConnectionStrings:MyDiaryDb" "your-connection-string"

List all secrets

dotnet user-secrets list

Clear all secrets

dotnet user-secrets clear

Azure CLI login (for local Key Vault access)

az login


Common Mistakes

1. Key Vault without environment check

// Crashes locally if no Azure credentials 
  builder.Configuration.AddAzureKeyVault(keyVaultUrl, new DefaultAzureCredential());

2. Secrets in appsettings.json committed to Git

// DON'T — this goes into source control 
{
    "ConnectionStrings": {
        "MyDiaryDb": "Server=prod;Password=secret123;"
    }
}

3. Using Production profile for local development

// Ensure your local profile uses Development 
{
    "Dev": {
        "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
        }
    }
}

4. Assuming User Secrets work in Production

They don't. User Secrets are Development-only by design.


References