asp.net core
appsettings.json
environment configuration
devops
software development

Automatically set appsettings.json for dev and release environments in asp.net core?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

ASP.NET Core uses environment-specific configuration files (appsettings.Development.json, appsettings.Production.json) that automatically override values in the base appsettings.json. The framework determines which file to load based on the ASPNETCORE_ENVIRONMENT environment variable. Settings in the environment-specific file merge with the base file, so you only need to specify values that differ per environment. This system eliminates the need for build-time config transforms used in older ASP.NET.

How Configuration Loading Works

csharp
1// Program.cs (ASP.NET Core 6+)
2var builder = WebApplication.CreateBuilder(args);
3
4// CreateBuilder automatically loads configuration in this order:
5// 1. appsettings.json (always loaded)
6// 2. appsettings.{Environment}.json (overrides matching keys)
7// 3. User secrets (Development only)
8// 4. Environment variables
9// 5. Command-line arguments
10
11// Later sources override earlier ones
12var connectionString = builder.Configuration.GetConnectionString("Default");

The configuration system is additive. appsettings.Production.json does not replace appsettings.json — it merges on top of it. Only keys present in the environment file are overridden.

File Structure

 
1MyApp/
2├── appsettings.json                    # Base settings (all environments)
3├── appsettings.Development.json        # Development overrides
4├── appsettings.Staging.json            # Staging overrides
5├── appsettings.Production.json         # Production overrides
6└── Program.cs
json
1// appsettings.json — base configuration
2{
3    "ConnectionStrings": {
4        "Default": "Server=localhost;Database=MyApp;Trusted_Connection=true"
5    },
6    "Logging": {
7        "LogLevel": {
8            "Default": "Warning"
9        }
10    },
11    "AllowedHosts": "*",
12    "Features": {
13        "EnableSwagger": false,
14        "MaxPageSize": 100
15    }
16}
json
1// appsettings.Development.json — overrides for local development
2{
3    "ConnectionStrings": {
4        "Default": "Server=localhost;Database=MyApp_Dev;Trusted_Connection=true"
5    },
6    "Logging": {
7        "LogLevel": {
8            "Default": "Debug",
9            "Microsoft.AspNetCore": "Information"
10        }
11    },
12    "Features": {
13        "EnableSwagger": true
14    }
15}
json
1// appsettings.Production.json — overrides for production
2{
3    "ConnectionStrings": {
4        "Default": "Server=prod-db.internal;Database=MyApp;User Id=app;Password=***"
5    },
6    "Logging": {
7        "LogLevel": {
8            "Default": "Error"
9        }
10    }
11}

In Development, EnableSwagger is true (overridden) and MaxPageSize is 100 (inherited from base). In Production, EnableSwagger is false (base value) since appsettings.Production.json does not override it.

Setting the Environment

bash
1# Windows (PowerShell)
2$env:ASPNETCORE_ENVIRONMENT = "Development"
3dotnet run
4
5# Windows (Command Prompt)
6set ASPNETCORE_ENVIRONMENT=Development
7dotnet run
8
9# Linux / macOS
10export ASPNETCORE_ENVIRONMENT=Development
11dotnet run
12
13# Or inline
14ASPNETCORE_ENVIRONMENT=Production dotnet run
xml
1<!-- launchSettings.json — used by Visual Studio and dotnet run -->
2{
3    "profiles": {
4        "MyApp": {
5            "commandName": "Project",
6            "environmentVariables": {
7                "ASPNETCORE_ENVIRONMENT": "Development"
8            },
9            "applicationUrl": "https://localhost:5001;http://localhost:5000"
10        }
11    }
12}

launchSettings.json is only used during local development. In production, set the environment variable on the server, in the Docker container, or in the hosting platform.

Checking the Environment in Code

csharp
1var builder = WebApplication.CreateBuilder(args);
2var app = builder.Build();
3
4// Check environment
5if (app.Environment.IsDevelopment())
6{
7    app.UseDeveloperExceptionPage();
8    app.UseSwagger();
9    app.UseSwaggerUI();
10}
11
12if (app.Environment.IsProduction())
13{
14    app.UseExceptionHandler("/error");
15    app.UseHsts();
16}
17
18// Custom environment check
19if (app.Environment.IsEnvironment("Staging"))
20{
21    // Staging-specific middleware
22}

Strongly Typed Configuration

csharp
1// Settings class
2public class FeatureSettings
3{
4    public bool EnableSwagger { get; set; }
5    public int MaxPageSize { get; set; }
6}
7
8// Registration in Program.cs
9builder.Services.Configure<FeatureSettings>(
10    builder.Configuration.GetSection("Features"));
11
12// Injection in a controller or service
13public class ProductsController : ControllerBase
14{
15    private readonly FeatureSettings _features;
16
17    public ProductsController(IOptions<FeatureSettings> options)
18    {
19        _features = options.Value;
20    }
21
22    [HttpGet]
23    public IActionResult Get()
24    {
25        var pageSize = _features.MaxPageSize;
26        // ...
27    }
28}

Bind configuration sections to C# classes with IOptions<T>. The values automatically reflect the merged configuration for the current environment.

Docker and CI/CD

dockerfile
1# Dockerfile
2FROM mcr.microsoft.com/dotnet/aspnet:8.0
3WORKDIR /app
4COPY publish/ .
5
6# Set environment at container level
7ENV ASPNETCORE_ENVIRONMENT=Production
8
9ENTRYPOINT ["dotnet", "MyApp.dll"]
yaml
1# docker-compose.yml
2services:
3  web:
4    image: myapp
5    environment:
6      - ASPNETCORE_ENVIRONMENT=Production
7      - ConnectionStrings__Default=Server=db;Database=MyApp;User Id=app;Password=secret

In Docker, use environment variables for secrets instead of appsettings.Production.json. The __ (double underscore) separator maps to the : hierarchy in JSON configuration.

User Secrets for Development

bash
1# Initialize user secrets for the project
2dotnet user-secrets init
3
4# Set a secret
5dotnet user-secrets set "ConnectionStrings:Default" "Server=localhost;Database=Dev;Password=secret"
6
7# List secrets
8dotnet user-secrets list

User secrets store sensitive values outside the project directory (in ~/.microsoft/usersecrets/), keeping them out of source control. They are loaded automatically in the Development environment.

Common Pitfalls

  • Not setting ASPNETCORE_ENVIRONMENT in production: The default environment is Production, but many hosting platforms do not set the variable. If middleware behaves unexpectedly, verify the variable is set with app.Environment.EnvironmentName.
  • Committing secrets in appsettings.Production.json: Environment-specific files are tracked by git. Use environment variables or a secrets manager (Azure Key Vault, AWS Secrets Manager) for passwords and API keys in production.
  • Expecting full replacement instead of merge: appsettings.Development.json merges with appsettings.json. If the base file has a key, it carries into all environments unless explicitly overridden. To "remove" a key, set it to null or an empty value.
  • launchSettings.json in production: launchSettings.json is ignored outside dotnet run and Visual Studio. Setting ASPNETCORE_ENVIRONMENT there has no effect in Docker, IIS, or Kestrel started directly.
  • Case sensitivity on Linux: File names are case-sensitive on Linux. appsettings.development.json does not match Development. Use exact casing: appsettings.Development.json.

Summary

  • ASP.NET Core loads appsettings.json first, then appsettings.{Environment}.json as an override
  • Set ASPNETCORE_ENVIRONMENT to Development, Staging, or Production to select the file
  • Environment-specific files merge with the base file — only overridden keys change
  • Use IOptions<T> for strongly typed configuration that reflects the current environment
  • Use environment variables or user secrets for sensitive values — never commit passwords to config files
  • In Docker, use ENV or docker-compose environment variables with __ as the hierarchy separator

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design