appsettings.json layering works like a .env you can nest

Configuration is assembled from several sources in order, each overriding the last, with environment variables last — so the same file works in development and is overridden in production without a second copy.

// appsettings.json — committed, the defaults
{ "ConnectionStrings": { "Shop": "Server=localhost;Database=shop" } }

// appsettings.Production.json — overrides, per environment
// and finally, from the environment:
//   ConnectionStrings__Shop=Server=db-01;Database=shop
// the double underscore is the nesting separator

The double underscore mapping is what makes deep structure expressible in a flat environment variable, which is the part a .env cannot do. Values arrive typed, so a port is an integer rather than the string every PHP application has to cast. The trap is the same as everywhere: the environment-specific file is chosen by an environment variable, and getting that wrong loads the development configuration in production quietly.