ASP.NET Core and Docker Environment Variables


Docker Logo

When working with ASP.NET Core and Docker, it can be easy to get confused when trying to figure out who is setting what configuration variable and how. Especially if you are using one of the Visual Studio templates with Docker support.

In this article, we’re going to take a look at how configuration settings are applied in both ASP.NET Core, and Docker, and how they interoperate.


Let’s start with a crash course on ASP.NET Core configuration handling.

Configuration Builder

In the typical ASP.NET Core application, you’ll find something in your Startup class, similar to the following:

var configuration = new ConfigurationBuilder()

This is where external configuration variables meet ASP.NET Core. This is similar to the web.config and ConfigurationManager classes you may have used before when using the .NET Framework (ASP.NET 4.x), but instead of using IIS and config transforms, we are using multiple sources to build up our configuration.

The ConfigurationBuilder uses a builder pattern and you can create your own extensions to support your configuration store of choice (maybe Azure Key Vault or Table Storage), but these AddJsonFile and AddEnvironmentVariables builder methods are the most common.

The JSON file is our replacement for the appSettings element within web.config, whilst the environment variables are the environment variables on the host platform. For example in IIS we might have: USERNAME, APP_POOL_ID, and SystemDrive. On my Windows 10 machine using IIS Express, I counted a total of 71 environment variables.

As each method builds up your configuration, any duplicate keys will get overwritten. So, if each configuration store has a variable called Duplicate, we'd see the following:

var configuration = new ConfigurationBuilder()
  .AddJsonFile("appsettings.json") // Duplicate == Json1
  .AddJsonFile($"appsettings.{env.EnvironmentName}.json") // Duplicate == Json1
  .AddEnvironmentVariables() // Duplicate == Environment

Where the final value is "Environment". So, start with your generic settings and then override them with your platform/environment specifics.

Once built we receive a basic key value store of IConfigurationRoot which can also be used as IConfiguration.


This configuration abstraction then hooks into the IOptions abstraction, which uses your configuration (or specific parts of it) to populate objects that represent your configuration settings. No more self-implemented logic just to pull out settings from the web.config!

You might see this in action like so:


Where EmailConfiguration just contains some properties with getters and setters. This can then later be retrieved as:

public EmailService(IOptions<EmailConfiguration> options) {
    EmailConfiguration config = options.Value;

We could access everything directly by key through IConfiguration, but this approach is a lot more readable and maintainable.

Docker Environment Variables

Docker has support for environment variables to be set in a variety of different ways, and these Docker environment variables are loaded automatically into our ASP.NET Core application as part of the AddEnvironmentVariables method. It’s that simple.

Docker File

Docker allows environment variables to be configured in a Docker file using the ENV instruction. This instruction takes a key value pair, separated by a space or an equals character. For example:

ENV EmailServer=127.0.01
ENV ConnectionString= Data Source=127.0.01,1500;Initial Catalog=Test.Database;

See the Docker reference documentation for more details.

Docker Run

We can then override the environment variables set in the Docker file when running the image by using the -e flag:

Docker run -e "EmailServer=" myimage

Docker Compose

Docker Compose also supports environment variables to be set as part of a container’s configuration:

    - EmailServer=

ASP.NET Core Environment

To set which environment we are using and keep using IHostingEnvironmnet we can use the key ASPNETCORE_ENVIRONMENT (previously ASPNETCORE_ENV). This would typically be a value such as Development, Staging, or Production.

JSON Sections

We can also handle configuration sections used in JSON files, such as:

"Logging": {
  "IncludeScopes": false,
  "LogLevel": {
    "Default": "Debug",
    "System": "Information",
    "Microsoft": "Information"

These we access via a colon delimiter, for example: "Logging:LogLevel:Default". This way we can keep using our configuration sections.

Share this article: