Hosting environment: Production and Now listening on: http://localhost:5000 from an app that said Development and its own port a minute ago? You ran dotnet run --no-launch-profile, which skips Properties/launchSettings.json, and that file is where both the environment and the URL came from. Run with the profile, or set the environment yourself.

The quickest fixes are dotnet run --launch-profile http, or keeping the flag and passing the settings to the app after a double dash: dotnet run --no-launch-profile -- --environment Development. On the .NET 10 SDK, leaving out that -- silently does nothing for the app.

The error

There is no error, only different startup lines. With the launch profile (paths shortened, nothing else changed):

Using launch settings from ...\w1\Properties\launchSettings.json...
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:15910
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

The same project with dotnet run --no-launch-profile:

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: ...\w1

And what the test script logged when it fetched two endpoints from each run, with the profile first:

GET http://localhost:15910/ -> 200; body length 75
Environment: Development, Greeting: Hello from appsettings.Development.json
GET http://localhost:15910/boom -> 500; Content-Type 'text/plain; charset=utf-8'; body length 531

GET http://localhost:5000/ -> 200; body length 44
Environment: Production, Greeting: (not set)
GET http://localhost:5000/boom -> 500; Content-Type ''; body length 0

Why it happens

launchSettings.json is a development-time file that dotnet run and Visual Studio read; the app itself never opens it. Its http profile supplies ASPNETCORE_ENVIRONMENT=Development and an applicationUrl. Skip it and neither arrives: the host falls back to Production and Kestrel to http://localhost:5000.

Everything that depends on the environment changes with it. The builder looks for appsettings.Production.json instead of appsettings.Development.json, so the Greeting value was missing, and the developer exception page is only switched on in Development, so the failing endpoint returned an empty 500 instead of a stack trace. In a Blazor app the same switch also empties every CSS and JS file, as the MapStaticAssets post shows.

The trap: dotnet run --no-launch-profile --environment Development still logged Production on SDK 10.0.401. dotnet run --help on SDKs 9.0.317 and 10.0.401 lists its own -e, --environment <NAME="VALUE"> option, so the SDK took the flag, set a variable literally named Development to an empty string, and passed the app no arguments. On SDK 8.0.425 the same command reached the app and gave Development.

The fix

# Simplest: use the profile, or name it
dotnet run --launch-profile http

# Keep --no-launch-profile: pass environment and port to the app after --
dotnet run --no-launch-profile -- --environment Development --urls http://localhost:15912

# Or let the SDK set the variable for the app
dotnet run --no-launch-profile -e ASPNETCORE_ENVIRONMENT=Development -- --urls http://localhost:15914

# Or set it for the process (PowerShell), then run as before
$env:ASPNETCORE_ENVIRONMENT = "Development"
dotnet run --no-launch-profile

All four logged Hosting environment: Development, returned the Greeting and gave the stack trace back on the failing endpoint. Note that the last one still listened on port 5000: the environment variable fixes the environment, not the URL, which also came from the profile. DOTNET_ENVIRONMENT=Development worked the same way when ASPNETCORE_ENVIRONMENT was not set.

How it was reproduced

A dotnet new web project on the .NET SDK 10.0.401 (ASP.NET Core runtime 10.0.12), with the template's http profile moved to port 15910, a Greeting value in appsettings.Development.json, and the endpoints below. Each command was started by a script from a shell with no ASPNETCORE_ or DOTNET_ENVIRONMENT variables, probed with Invoke-WebRequest and stopped. The SDK 8 comparison used a net8.0 copy pinned to SDK 8.0.425 with global.json.

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

app.MapGet("/", (IConfiguration config, IHostEnvironment env) =>
    $"Environment: {env.EnvironmentName}, Greeting: {config["Greeting"] ?? "(not set)"}");

app.MapGet("/boom", string () => throw new InvalidOperationException("Something broke"));

// Diagnostics for the experiment: what reached the app?
app.MapGet("/args", () =>
    $"args: [{string.Join(", ", args)}], variable 'Development': " +
    (Environment.GetEnvironmentVariable("Development") is { } v ? $"set to '{v}'" : "not set"));

app.Run();

Frequently asked

Why does my ASP.NET Core app say Hosting environment: Production with dotnet run?
You probably ran it with --no-launch-profile. The Development setting normally comes from the launch profile in Properties/launchSettings.json, and with no environment set the host defaults to Production.
Why does dotnet run --no-launch-profile listen on port 5000?
The port in launchSettings.json is part of the skipped profile. With no URL configured anywhere, Kestrel listens on http://localhost:5000. Pass --urls after a double dash, or run with --launch-profile.
Why does dotnet run --environment Development not work on .NET 10?
On the .NET 10 SDK, dotnet run has its own -e, --environment option that sets environment variables in NAME=VALUE form, so it consumes the flag instead of passing it to your app. Write dotnet run --no-launch-profile -- --environment Development, where the double dash hands the rest to the app, or use the SDK option as intended: -e ASPNETCORE_ENVIRONMENT=Development.

More decoded errors in the Fixes category, including another dotnet run switch that lands somewhere you did not expect.