aspnet-configuracion-entornos

Configuring Environments in ASP.NET Core

  • 5 min

An environment in ASP.NET Core is the context in which an application runs and allows changing its configuration and behavior depending on whether we are in development, testing, or production.

This allows us to adapt the application’s behavior: debug locally, test changes in staging, and apply stricter configuration in production. Because running an API on your local machine is one thing, but deploying it on a server with real users watching is quite another.

For example, in Development we can show detailed errors and enable Swagger. In Production, the norm is to hide internal details, enable HSTS, use real configuration, and log errors in a controlled manner.

Common Environments

ASP.NET Core allows using any environment name, but three names appear constantly:

  • Development: local development environment with debugging tools and detailed error messages.
  • Staging: testing environment similar to production, useful for validating deployments before going live.
  • Production: real environment, optimized for security, performance, and stability.

If no environment is configured, ASP.NET Core assumes Production by default. This makes sense, as it’s preferable to start in safe mode rather than showing an error page with all internal details.

Environment Variables

The environment is typically set via an environment variable. The most common one in ASP.NET Core applications is ASPNETCORE_ENVIRONMENT.

$env:ASPNETCORE_ENVIRONMENT="Development"
Copied!

On Linux or macOS:

export ASPNETCORE_ENVIRONMENT=Development
Copied!

There is also DOTNET_ENVIRONMENT, which applies to the .NET generic host. In modern projects using WebApplication.CreateBuilder, it’s best to not define both with different values, otherwise you’re asking for an entertaining afternoon of diagnosis.

Environment variable names are case-sensitive on Linux. ASPNETCORE_ENVIRONMENT and aspnetcore_environment are not the same.

launchSettings.json

When working locally, Visual Studio, Rider, or dotnet run can use the Properties/launchSettings.json file. This file is intended for local development and is not published with the application.

{
  "profiles": {
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Staging": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": false,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Staging"
      }
    }
  }
}
Copied!

We can run a specific profile from the CLI:

dotnet run --launch-profile Staging
Copied!

To ignore local profiles and use what’s set in the console:

dotnet run --no-launch-profile
Copied!

Environment-specific appsettings

ASP.NET loads configuration files specific to the environment. The pattern is:

appsettings.{Environment}.json
Copied!

For example:

appsettings.json
appsettings.Development.json
appsettings.Staging.json
appsettings.Production.json
Copied!

The idea is simple: appsettings.json contains the base configuration, and the environment-specific file overrides the keys that need changing.

appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=prod-sql;Database=MiApp;..."
  }
}
Copied!

appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MiAppDev;..."
  }
}
Copied!

This way, the same application can use more logging and a local database in development, but connect to the real configuration when running in production.

Priority Order

Configuration in ASP.NET Core comes from multiple sources. In the default setup, the usual order is:

  1. appsettings.json.
  2. appsettings.{Environment}.json.
  3. User Secrets (only in Development).
  4. Environment variables.
  5. Command-line arguments.

The key rule is: if the same key appears in multiple places, the source with higher priority wins.

That’s why an environment variable can override a value from appsettings.json, and a command-line argument can override almost everything before it.

For hierarchical keys in environment variables, use double underscore __ instead of colon :. For example, ConnectionStrings__DefaultConnection.

Changing Behavior by Environment

Sometimes changing configuration values is not enough. We might also want to enable or disable parts of the pipeline based on the environment.

A typical example is in Program.cs:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.Run();
Copied!

In development, we show a detailed error page. In production, we use a safe handler and enable HSTS.

We can also check for custom environments:

if (app.Environment.IsEnvironment("Testing"))
{
    // Specific configuration for automated tests
}
Copied!

Custom environments are valid. Just be consistent with the names and create the corresponding configuration files, like appsettings.Testing.json.

Setting the Environment in Production

In production, the environment is usually configured from the deployment platform.

In Azure App Service, we can set ASPNETCORE_ENVIRONMENT from the application settings:

  1. Go to the App Service.
  2. Navigate to Settings > Configuration > Application settings.
  3. Add ASPNETCORE_ENVIRONMENT with the value Production, Staging, or the appropriate one.

Azure restarts the application when these settings change, so the new environment applies on the next startup.

In Docker, we can define the environment in the Dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080

ENV ASPNETCORE_ENVIRONMENT=Production
Copied!

Or pass it when running the container:

docker run -e ASPNETCORE_ENVIRONMENT=Production my-app
Copied!

If using Docker Compose:

services:
  web:
    image: my-app
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
Copied!

Best Practices

Don’t store real secrets in appsettings.Production.json if that file goes into the repository. For development, use User Secrets. For production, use environment variables, Azure Key Vault, or another secret store.

Also, avoid cluttering the application with if (app.Environment.IsDevelopment()). It’s fine for simple pipeline differences. For larger differences, it’s usually better to use configuration or dependency injection.

For example, in development, we can register a FakeEmailSender, and in production, an SmtpEmailSender. The rest of the application doesn’t need to know where it’s running.