C# � �8 min read

Environment Variables Done Properly

Environment variables provide a simple and secure way to manage application configuration without hardcoding settings into your source code. Whether you're developing locally, deploying to production or running applications inside Docker containers, understanding how to use environment variables properly can make your applications easier to maintain, more secure and much more flexible.

Admin
Admin
.NET & IoT Developer
Environment Variables Done Properly

Managing application configuration is an important part of software development. As applications grow, they often need to connect to databases, communicate with external services, use API keys and behave differently depending on the environment in which they are running.

One of the biggest mistakes developers can make is hardcoding these settings directly into their application.

Environment variables provide a much better approach. They allow configuration to be separated from application code, making applications easier to deploy, maintain and secure.

In this article, we'll look at what environment variables are, how to use them in .NET applications, and some practical approaches to managing configuration across development, testing and production environments.

What Are Environment Variables?

Environment variables are named values made available to applications by the operating system or hosting environment.

They allow applications to retrieve configuration information without needing those values to be stored directly in the source code.

For example, an application might require a database connection string:

Server=localhost;Database=MyApplication;Trusted_Connection=True;

Rather than placing this connection string directly into your application, you can store it in an environment variable called:

ConnectionStrings__DefaultConnection

Your application can then retrieve the value when it starts.

This means the same application can run against different databases simply by changing its environment configuration, without requiring any changes to the code.

Why Should You Use Environment Variables?

There are several important reasons to use environment variables when developing applications.

Keeping Configuration Separate From Code

Application code should describe what an application does, rather than contain details about where it is running or which external services it needs to communicate with.

Separating configuration from code makes it easier to move applications between development, staging and production environments.

Improving Security

Sensitive information such as database passwords, API keys and authentication secrets should never be committed to source control.

Environment variables provide a way to supply these values outside your application source code.

Although environment variables are useful, they should not automatically be considered a secure secrets store. Access to the machine, container or hosting environment can potentially expose them. For production systems, dedicated secrets management solutions are often a better choice.

Simplifying Deployment

When configuration is externalised, deploying an application becomes much simpler.

You can deploy exactly the same application build to multiple environments and supply different configuration values depending on where it is running.

This is particularly useful when working with automated deployment pipelines and Docker containers.

Using Environment Variables in .NET

.NET provides built-in support for environment variables through its configuration system.

In a modern ASP.NET Core application, environment variables are automatically included as a configuration provider by default.

This means you can access them through IConfiguration without needing to write your own configuration code.

For example, consider the following environment variable:

MyApplication__ApiKey

The double underscore (__) is important because .NET uses it as a separator when translating environment variables into hierarchical configuration keys.

The corresponding configuration key becomes:

MyApplication:ApiKey

You can retrieve the value using:

var apiKey = configuration["MyApplication:ApiKey"];

Alternatively, you can inject IConfiguration into a service or controller:

public class ApiService
{
    private readonly IConfiguration _configuration;

    public ApiService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Initialise()
    {
        var apiKey = _configuration["MyApplication:ApiKey"];
    }
}

This approach keeps configuration access centralised and avoids scattering hardcoded settings throughout your application.

Understanding the Double Underscore Convention

One of the most useful features of environment variables in .NET is the ability to represent hierarchical configuration.

JSON configuration files commonly contain nested sections:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MyApplication;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

Environment variables cannot naturally use the same hierarchical structure, so .NET uses double underscores to represent section separators.

The equivalent environment variables would be:

ConnectionStrings__DefaultConnection
Logging__LogLevel__Default

This makes it possible to override individual configuration values without replacing an entire configuration file.

It is worth remembering that environment variable names are generally treated as case-insensitive by .NET configuration.

Managing Environment Variables During Development

When developing locally, you need a convenient way to provide configuration without committing sensitive information to your repository.

.NET provides a feature called User Secrets that is particularly useful for this purpose.

User Secrets allows developers to store sensitive development configuration outside the project directory.

To initialise User Secrets, open a terminal in your project directory and run:

dotnet user-secrets init

This adds a UserSecretsId to your project file.

You can then add a secret:

dotnet user-secrets set "MyApplication:ApiKey" "your-development-api-key"

Your application can access this value through the normal .NET configuration system.

For example:

var apiKey = builder.Configuration["MyApplication:ApiKey"];

User Secrets are intended for development rather than production. They are not encrypted and should not be treated as a secure storage solution for deployed applications.

However, they provide a much better alternative to placing passwords and API keys inside appsettings.json.

Using appsettings.json Alongside Environment Variables

Environment variables do not mean you need to stop using appsettings.json.

In fact, combining the two approaches is often the best solution.

Your appsettings.json file can contain non-sensitive default configuration:

{
  "Application": {
    "Name": "My Application",
    "Version": "1.0"
  },
  "ConnectionStrings": {
    "DefaultConnection": ""
  }
}

You can then supply the actual connection string through an environment variable:

ConnectionStrings__DefaultConnection

.NET's default configuration system loads multiple configuration providers in a defined order. Environment variables are loaded after the standard JSON configuration files, meaning they take precedence when the same setting exists in both places.

This gives you sensible defaults while allowing deployment environments to override individual settings.

Setting Environment Variables in Windows

If you are developing on Windows, there are several ways to configure environment variables.

You can use PowerShell to create a temporary environment variable for the current session:

$env:MyApplication__ApiKey = "your-api-key"

This value is available to processes started from that PowerShell session.

You can also use the Windows Environment Variables settings to create user-level or system-level variables.

User-level variables are available to applications running under your Windows account, while system-level variables are available to applications across the machine.

Be aware that applications generally need to be restarted before they see newly created environment variables.

For local development, PowerShell is particularly useful because it allows you to quickly test different configuration values without permanently changing your machine.

Environment Variables and Docker

Environment variables become particularly useful when working with Docker.

Rather than including environment-specific configuration inside your Docker image, you can supply values when creating a container.

For example, using Docker Compose:

services:
  web:
    image: myapplication:latest
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ConnectionStrings__DefaultConnection: ${DB_CONNECTION}

The ${DB_CONNECTION} value is supplied from the environment running Docker Compose or an appropriate environment file.

Alternatively, you can provide an environment file:

services:
  web:
    image: myapplication:latest
    env_file:
      - .env

Your .env file might contain:

DB_CONNECTION=Server=myserver;Database=MyApplication;User Id=myuser;Password=mypassword;

Make sure files containing real credentials are excluded from source control using .gitignore.

Also remember that Docker environment variables are visible to users who have sufficient access to inspect the container. For sensitive production credentials, consider Docker secrets or an external secrets management service.

Keeping configuration outside your Docker image means you can build an image once and reuse it across multiple environments.

Choosing the Right Configuration Approach

Not every configuration value needs to be an environment variable.

A useful approach is to decide where each type of configuration belongs.

Non-sensitive application defaults, such as logging levels, feature settings and display preferences, are generally suitable for appsettings.json.

Development-only credentials and API keys are good candidates for .NET User Secrets.

Environment-specific settings, such as database endpoints and external service URLs, can be supplied through environment variables.

Production secrets, including database passwords, API keys and certificates, are better managed through dedicated secrets management solutions where possible.

For example, Azure Key Vault provides a centralised way to store and retrieve application secrets without placing them directly in deployment configuration.

The important thing is to avoid treating every configuration value in exactly the same way.

Common Mistakes to Avoid

One common mistake is committing passwords or API keys to source control. Even if you remove them in a later commit, the original values may still exist in the repository history.

Another mistake is assuming environment variables are automatically secure. They are simply configuration values supplied by the operating system or hosting environment, and anyone with sufficient access may be able to retrieve them.

Developers should also avoid using different configuration names across environments. Keeping naming conventions consistent makes deployments much easier to understand and troubleshoot.

Finally, avoid assuming that changing an environment variable will automatically update a running application. Most applications read their configuration during startup, so a restart or an explicit configuration reload mechanism may be required.

Final Thoughts

Environment variables are a straightforward but important part of building maintainable applications.

By separating configuration from application code, you can create software that is easier to deploy, more flexible and less likely to expose sensitive information.

For .NET developers, the built-in configuration system makes working with environment variables particularly simple. Combining appsettings.json, User Secrets and environment-specific configuration provides a practical approach that works just as well for small projects as it does for larger applications.

Whether you are developing a local Blazor application, building an ASP.NET Core API or deploying a .NET application inside Docker, getting your configuration management right from the beginning can save a considerable amount of time later.

The golden rule is simple: keep configuration out of your code, keep secrets out of source control, and make sure each environment receives the settings it actually needs.

Share:

Become a member

Get the latest news right in your inbox. It's free and you can unsubscribe at any time. We hate spam as much as we do, so we never spam!

Read next

When to Use Records in C#

C# records provide a concise way to represent data where the values themselves matter more than the identity of the object. Introduced in C# 9, records include built-in value-based equality, concise syntax and support for immutable data models. But records are not a replacement for classes everywhere. Knowing when to use a record, and when to stick with a class, can make your C# code cleaner and easier to maintain.

Admin 19-Aug-2026

The Bedroom Coder — retro computers, modern .NET, and late-night experiments.

Navigation

Contact

Want to talk retro tech or modern coding? I'd love to hear your thoughts.

© 2026 The Bedroom Coder. All rights reserved.