Moving web.config to appsettings.json in ASP.NET Core

When an ASP.NET application moves from .NET Framework to ASP.NET Core, only part of its web.config becomes appsettings.json: the app settings and connection strings. Everything else in the file either becomes code in Program.cs, moves to the host, belongs to a library, or disappears because the feature it configured no longer exists. This guide is for the developer doing that move and for the IT manager who wants to know how much of it there is before the work is planned.

It assumes the target is .NET 10, the current long-term support release, supported until 14 November 2028. Our .NET Framework to .NET 10 migration guide covers the rest of the job.

Why the file cannot simply be copied

On .NET Framework, web.config does two jobs at once. It holds the application’s own settings, and it configures IIS and the ASP.NET pipeline itself: authentication, session state, error pages, request limits, modules and handlers. ASP.NET Core separates these. Settings are read from appsettings.json, environment variables and other providers. The pipeline is built in code, in Program.cs, as a list of middleware.

So a web.config built up over many years is really a list of decisions, some of them forgotten. The move is the moment each one has to be found and made again, on purpose.

What goes wrong when it is done by hand

  • Settings read in code that nobody remembers. ConfigurationManager.AppSettings["X"] can be called from anywhere, including class libraries. If a key is missed, the application starts and fails later, on the one screen that used it.
  • Secrets end up in source control. web.config files often hold passwords in connection strings, SMTP settings and API keys. Copied straight into appsettings.json, they get committed with the code.
  • Behaviour changes silently. A request size limit, a session timeout, a culture setting or a custom error page that was set in web.config falls back to the ASP.NET Core default if nobody carries it over. Nothing fails at build time.
  • Transforms are forgotten. Web.Release.config and other transform files hold the real production values. Converting only the base file gives an application that works on a developer’s machine and not on the server.
  • IIS rules are lost. URL Rewrite rules, custom headers and MIME types under system.webServer are easy to overlook because they never appear in the code.

Doing it by hand: the steps

  1. Collect every config file. The base web.config, every transform, and any files it points to with configSource or file attributes. Note which environment each transform belongs to.
  2. Find every place settings are read. Search the whole solution for ConfigurationManager, WebConfigurationManager and ConnectionStrings. That list, not the file, tells you which settings are live.
  3. Move app settings and connection strings. App settings become keys in appsettings.json; keys written as Section:Name become nested sections. Connection strings go under a ConnectionStrings section, read with GetConnectionString("Name"). Replace each ConfigurationManager call with injected configuration, ideally bound to a typed options class.
  4. Take the secrets out. Blank passwords and keys in appsettings.json. Use user secrets on developer machines and environment variables or a secrets store on the server. In environment variable names, a double underscore stands for the colon, so Smtp:Password becomes Smtp__Password.
  5. Rebuild system.web in Program.cs. Each section has a replacement: forms authentication becomes cookie authentication; customErrors becomes the exception handler and status code pages middleware; sessionState becomes the session middleware with a cache behind it; globalization becomes request localisation; machineKey becomes Data Protection; HTTP modules and handlers become middleware. Membership providers have no direct equivalent and need a decision, usually ASP.NET Core Identity.
  6. Deal with system.webServer. Rewrite rules can be saved as a separate XML file and loaded by ASP.NET Core’s rewrite middleware with AddIISUrlRewrite. Static file MIME types, custom headers and request limits become middleware or server options. If the site will still run on IIS, the published web.config stays for the hosting module, and IIS-level settings such as maxAllowedContentLength can stay there too.
  7. Drop what no longer applies. Assembly binding redirects, compilation settings, trust levels and httpRuntime targetFramework have no meaning on modern .NET.
  8. Carry the transforms over. Each transform’s differences go into appsettings.Production.json or the matching environment file, chosen by the ASPNETCORE_ENVIRONMENT variable.
  9. List the custom sections. Sections registered under configSections belong to libraries such as log4net, Unity or Quartz. Each library documents its own setup on modern .NET, and some have no modern version at all.

The checks before you call it done

  • Every key found in step 2 exists in the new configuration, or has been deliberately dropped.
  • No password or key is committed in any appsettings file.
  • Upload limits, timeouts and session lengths match the old values, or the change is agreed.
  • Error pages, redirects and security headers behave the same, checked against the live site.
  • The application starts with production settings in a test environment, not only on a developer machine.

The shortcut

We built the free web.config to appsettings.json converter to do the mechanical part of this. Paste a web.config and it produces the appsettings.json, with secrets blanked and listed, the rewrite rules as a separate file, and a note for every other section saying where it goes, with Program.cs code where the mapping is direct. It runs in your browser and the file is not sent anywhere.

It does not replace steps 2, 8 and 9: it cannot see your code, apply transforms or configure third-party libraries. What it gives is a complete list of what the file contains and what each part becomes, which is the starting point for the estimate and the work.

For an application with many projects, also check the packages before starting: the NuGet upgrade planner checks each package for a release that supports modern .NET.

The converter is free, with no account or sign-up: web.config to appsettings.json converter.

Tell us about your system

Say what it does, what it is built on and what is worrying you. We will reply with what we would look at first and whether we are the right people to help.

Tell us about your system 0800 433 7990 Monday to Friday, 9am to 5pm. A first 20-minute call is free, and we reply to every enquiry within one working day. What happens after you get in touch