.NET Core
appsettings
environment variables
configuration management
application development

Merging appsettings with environment variables in .NET Core

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In .NET, configuration is usually not a manual merge that you write yourself. Instead, you add configuration providers in order, and later providers override earlier ones. That is why appsettings.json plus environment variables works well: JSON provides the baseline, and environment variables can replace selected values at runtime.

Configuration Providers Are Layered in Order

The important rule is simple:

  • add appsettings.json first
  • add environment variables later
  • later providers win when keys overlap

A minimal example with ConfigurationBuilder looks like this:

csharp
1using Microsoft.Extensions.Configuration;
2
3var configuration = new ConfigurationBuilder()
4    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
5    .AddEnvironmentVariables()
6    .Build();
7
8Console.WriteLine(configuration["ConnectionStrings:DefaultConnection"]);

If the same key exists in both sources, the environment variable value overrides the JSON value.

Map Nested JSON Keys With Double Underscores

Nested configuration keys in .NET use : as the logical separator, but environment variables usually represent that separator with double underscores.

For example, this JSON:

json
1{
2  "ConnectionStrings": {
3    "DefaultConnection": "Server=dev;Database=app;"
4  }
5}

can be overridden with an environment variable named:

text
ConnectionStrings__DefaultConnection

That tells the configuration system to replace:

ConnectionStrings:DefaultConnection

with the environment-provided value.

A Practical Example

Suppose appsettings.json contains:

json
1{
2  "Logging": {
3    "LogLevel": {
4      "Default": "Information"
5    }
6  }
7}

Then an environment variable such as:

text
Logging__LogLevel__Default=Warning

overrides the JSON value at runtime without modifying the file. This is especially useful in containers, CI pipelines, and cloud deployments where the same application artifact runs in several environments.

Why This Pattern Is Useful

Using JSON plus environment variables gives you a clean separation:

  • files hold default configuration
  • environment variables hold environment-specific overrides
  • secrets can be injected without hardcoding them into source control

That means one build artifact can move from development to staging to production without changing the code or rewriting the base settings file.

Prefer the Built-In Host Configuration

In modern ASP.NET Core apps, you often do not need to build this manually because the default host builder already includes JSON files and environment variables in the configuration pipeline. But it is still important to understand the merge order, especially when debugging why one value is winning over another.

If a setting seems wrong at runtime, the first question should be:

  • which providers were added
  • in what order
  • which provider supplied the final value

That is usually the real answer behind "merging" behavior.

It also explains why the same application can behave differently across environments even when the JSON file is identical: the active environment may be providing different overrides through host configuration.

That is especially common in containers and cloud platforms, where deployment manifests or hosting dashboards inject environment variables outside the repository and outside the published application files.

Many applications also insert environment-specific JSON files such as appsettings.Production.json between the base JSON file and environment variables. The same ordering rule still applies: providers added later override earlier values, so environment variables remain a final override layer.

Common Pitfalls

  • Thinking configuration sources are combined symmetrically rather than overridden in provider order.
  • Using single underscores instead of double underscores for nested environment-variable keys.
  • Forgetting that the environment variable must match the full configuration path exactly.
  • Assuming the JSON file is wrong when an environment variable is silently overriding it.
  • Storing secrets in appsettings.json even though the environment is supposed to provide them.

Summary

  • In .NET, configuration merging is provider layering, not hand-written merge logic.
  • Add appsettings.json first and environment variables later so environment values override defaults.
  • Use double underscores in environment variable names to represent nested configuration keys.
  • This pattern is ideal for environment-specific overrides and secret injection.
  • When a value looks wrong, check provider order before changing the JSON file.

Course illustration
Course illustration

All Rights Reserved.