Managing Environments in ASP.NET Core
1. Introduction
Managing multiple environments is mostly a DevOps concern, but every developer should be familiar with it. This post covers how .NET environment variables work: what they are, why they’re useful, and how to set and read them.
2. The Theory
2.1. Why Manage Multiple Environments?
Splitting environments is a core DevOps principle, and it earns its keep. You want your development environment isolated from production so developers can experiment and iterate on new features without the fear of accidentally breaking the live product. Controlled deployments reduce risk, improve maintainability, and keep the overall system stable. Isolating production also helps with data security; accidental leaks and unauthorized access become much harder when prod is walled off.
The reason I care about it most, though, is configuration management. Each environment typically needs a different set of configurations. In Development, you might serve JavaScript and CSS unminified for easier debugging, and keep the developer exception page on. In Production, you’d serve minified static files for performance, and you definitely don’t want that exception page on. It can leak sensitive information to users, or hand useful details to attackers. Conditional configuration is exactly what environment variables are for.
2.2. What Are .NET Environment Variables?
ASP.NET Core looks for an environment variable named ASPNETCORE_ENVIRONMENT at startup to figure out which environment it’s in. An environment variable is a named value defined at the OS level that persists across reboots. Think of it as a static string your operating system holds onto, and your projects read it to pick a configuration.
By convention the value is Development, Staging or Production, but you can set it to anything. If it’s not set at all, ASP.NET Core assumes Production, which is convenient since you don’t need to set it explicitly on prod.
Tip: When you run your application using dotnet run (or when you click the green “start” button in Visual Studio, which runs this command 🙂), the current hosting environment will be printed to the console.

It is possible to use the --environment parameter with the dotnet run command to specify the environment, which would look like:
dotnet run --environment StagingHowever, I would recommend against using this method and using launch profiles instead (which I’ll cover next).
In case you have environment variable defined on OS-level and want to run the application without any launch profiles (which is an obscure scenario, but I suppose this is good to know), you can run the following command:
dotnet run --no-launch-profile2.3. The Role Of Launch Profiles
Launch profiles, defined in Properties/launchSettings.json, describe ways to run your .NET application, each profile carrying its own options. They can set the environment variable too (default: Development), and when a profile sets it, the system-level value is ignored.
Visual studio provides a convenient way to modify launch profiles via the dedicated “debug launch profiles UI” which you can open by going to your project’s properties, switching to the “Debug” tab, and clicking “debug launch profiles UI”.

However, if you are like me, you will prefer to simply open up the launchSettings.json file and edit it directly. Here is what that would look like:

While launch profiles are a topic of their own, the relevant part for us here is the environmentVariables section (regardless of whether the profile is IIS or Kestrel). The launch profiles you get when you create a new project will set the environment variable to Development by default, which you should keep in mind. If you ever want to simulate a different environment within your development setup, you can set your desired environment in your launch profile.
Note: When using Visual Studio Code, you will have .vscode/launch.json which has a different structure, but the same ideas apply.
3. Setting the Environment Variable
There are a few ways to set the environment variable on a system, and the one you pick is mostly preference. Values in launchSettings.json override system-level ones, so during development you’ll usually rely on launch profiles. The approaches below mostly matter for non-development environments.
3.1. Using Command Line
You can set environment variables in Windows via command prompt using the setx command which comes with the OS. The setx command sets environment variables to the user or system environment. Since ASP.NET Core will look for the ASPNETCORE_ENVIRONMENT variable, that’s the variable we want to create. Here is the command:
setx ASPNETCORE_ENVIRONMENT Staging /M
dotnet run --no-launch-profileThe /M at the end instructs to set the environment variable at the system level, which is what I would recommend. If, for some reason, you want to set the environment variable for the user account, simply remove the /M.
--no-launch-profile parameter of dotnet run allows to ignore launch profile settings. You won’t need to do this if you are not running the project in Visual Studio.
3.2. Using PowerShell
Similar to using CMD in Windows, you can also use PowerShell to set environment variable:
$Env:ASPNETCORE_ENVIRONMENT = "Staging"
dotnet run --no-launch-profileOnce again, the --no-launch-profile parameter of dotnet run allows to ignore launch profile settings, which is irrelevant if you are not running the project in Visual Studio.
3.3. Using Windows Settings
It is also possible to set the environment variable in Windows GUI via “Environment Variables” settings. Similar to the preceding approaches, this will also set the environment variable globally on the system.
You can access the “Environment Variables” settings via “Control Panel > System > Advanced system settings > Environment Variables”. You can also simply search for “environment variables” in Windows:

From there, click “new” to add a new env. variable and provide a name and a value:

The env. variable name needs to be ASPNETCORE_ENVIRONMENT, and the variable name will specify the environment name (e.g., Staging, PreProd, etc.)
3.4. Using Web.Config File
If you would rather set the env. variable on a project basis rather than having a global env. variable for all projects on the system, you could use a web.config file on your project’s root directory, in the environment variables section. For example:
<aspNetCore processPath="dotnet"
arguments=".\MyApp.dll"
stdoutLogEnabled="false"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Staging" />
<environmentVariable name="CONFIG_DIR" value="f:\application_config" />
</environmentVariables>
</aspNetCore>3.5. Setting Environment Variable with Code
You can also set the env. variable from code. I wouldn’t recommend it in general, but it’s useful in certain scenarios. Here’s what that looks like in an ASP.NET Core project:
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
EnvironmentName = Environments.Staging
});4. Using Environment Variable
4.1. Environment-Based Project Configuration
Now for the practical part: reading the current environment so you can conditionally register middleware or services. For example:
#if DEBUG
if (builder.Environment.IsDevelopment())
mvcBuilder.AddRazorRuntimeCompilation();
#endifThis code checks both the “configuration” (which may be Debug or Release) and the current enviroment, and enables runtime compilation of Razor views if the current environment is “Development” and if the application is being built in debug mode.
Here are some useful methods you can use to read the current environment:
- IsDevelopment() : Returns
trueif the current environment isDevelopment - IsStaging() : Returns
trueif the current environment isStaging - IsProduction() : Returns
trueif the current environment isProduction - IsEnvironment(string environmentName) : Returns
trueif the current environment matches the specifiedenvironmentName
Here is an example piece of code you may find useful, which conditionally registers developer exception page during development and sets up custom exception handling in production:
if (app.Environment.IsDevelopment())
{
Log.Information("Development environment detected. Setting up developer exception page.");
app.UseDeveloperExceptionPage();
}
else
{
Log.Information("Production environment detected. Setting up global exception handler.");
app.UseStatusCodePagesWithRedirects("/Error/{0}");
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Run(async context =>
{
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
if (exceptionHandlerFeature == null) return;
var errorCode = Guid.NewGuid().ToString();
var exception = exceptionHandlerFeature.Error;
var userName = "Anonymous";
if (context.User.Identity?.IsAuthenticated == true)
userName = context.User.Identity.Name;
Log.Error(exception, "GLOBAL EXCEPTION HANDLED. Error Code: {ErrorCode}, User: {UserName}, Time: {Time}", errorCode, userName, DateTime.Now);
var redirectUrl = $"/error/500?errorCode={errorCode}";
context.Response.Redirect(redirectUrl);
});
});
}You can then handle this redirection and display an appropriate screen to inform users that an error has occurred, along with the error code, so they can provide it when contacting you.
4.2. Accessing Environment From Front-End (Razor)
You may also want to read the hosting environment from the front-end to render HTML conditionally. ASP.NET Core ships a built-in “environment” tag helper for exactly this. It accepts three parameters (names, include, and exclude), and you’ll typically only use one of them.
names and include behave identically: both accept a comma-separated list of environment names and render the content if any of them match the current environment.
<environment include="Development,Staging">
<p>
The current hosting environment is either Development or Staging.
</p>
</environment>exclude does the opposite — it renders its contents only when the current environment doesn’t match any of the listed values.
<environment exclude="Production">
<p>
The current hosting environment is anything but Production.
</p>
</environment>5. References
- ASP.NET Core Documentation
- Manning Books
- Andrew Lock