Upgrading from .NET 8 to .NET 10: A Practical Checklist
Why upgrade now November 10, 2026 is the end-of-support date for both .NET 8 and .NET 9. Your apps keep running after that date, but they stop receiving security patches, so every new vulnerability stays open. The targ
Why upgrade now
November 10, 2026 is the end-of-support date for both .NET 8 and .NET 9. Your apps keep running after that date, but they stop receiving security patches, so every new vulnerability stays open. The target is .NET 10, the current LTS release, supported until November 2028 (Microsoft .NET Blog).
The good news: for most apps on modern .NET this is a days-long job, not a months-long one. The breaking changes are targeted and documented, and most of them show up as compiler warnings. This checklist is the order I'd follow for a typical solution, plus the changes most likely to bite.
Before you start
Take inventory first, retarget second. Ten minutes here saves hours of guessing later.
- List every deployable project, test project and shared library in the solution.
- Find every place a version is pinned:
global.json, Dockerfiles, CI pipeline SDK versions, build scripts. - Check what your machine and pipeline actually resolve:
dotnet --list-sdks
dotnet --info
- Check your dependencies for outdated or abandoned packages:
dotnet list package --outdated
- Run your test suite on the current version and save the result. You want a known-good baseline to compare against.
- Create a dedicated branch. Keep the SDK bump, the package updates and the code fixes in separate commits so a failure is easy to locate.
The upgrade, step by step
1. Pin the SDK. Install the .NET 10 SDK and update global.json:
{
"sdk": {
"version": "10.0.100",
"rollForward": "latestFeature"
}
}
2. Change the target framework in every project (or once in Directory.Build.props if you centralize it):
<TargetFramework>net10.0</TargetFramework>
Upgrade shared libraries first, then the apps that depend on them. If other teams consume your libraries, multi-target for a while with <TargetFrameworks>net8.0;net10.0</TargetFrameworks>.
3. Update Microsoft packages to 10.0.x. That means Microsoft.AspNetCore.*, Microsoft.Extensions.* and Microsoft.EntityFrameworkCore.*. Keep their versions aligned with each other.
4. Restore and read the new warnings. dotnet restore now audits transitive packages by default, so expect vulnerability warnings you didn't see before. NuGet also flags direct references it can prune (NU1510), and a PackageReference without a version is now an error.
5. Build with warnings as errors. Obsolete APIs surface as SYSLIB and ASPDEPR diagnostics. This is the fastest way to find most of what needs fixing:
dotnet build -warnaserror
6. Run the tests and the app. Compare against your baseline. Many changes are behavioral, so a green build is not the finish line: run integration tests with real configuration and real payloads.
What actually breaks
Coming from .NET 8 you inherit the breaking changes of both .NET 9 and .NET 10. These are the ones most likely to affect a typical web app; the full lists are linked in Sources.
| Area | Change | What to do |
|---|---|---|
| ASP.NET Core |
WebHostBuilder, IWebHost and WebHost are obsolete |
Move to WebApplication.CreateBuilder or the generic host |
| ASP.NET Core |
IActionContextAccessor / ActionContextAccessor are obsolete |
Use IHttpContextAccessor instead |
| ASP.NET Core |
WithOpenApi() extension method is deprecated |
Remove it; the built-in generator now emits OpenAPI 3.1 by default. Pin 3.0 if your client generators need it |
| ASP.NET Core | Razor runtime compilation is obsolete | Rely on build-time compilation and Hot Reload |
| ASP.NET Core |
ForwardedHeadersOptions.KnownNetworks and IPNetwork are obsolete |
Switch to KnownIpNetworks with System.Net.IPNetwork
|
| ASP.NET Core | Cookie login redirects are disabled for known API endpoints | API calls now get 401/403 instead of a redirect; check clients that expected the redirect |
| Blazor | Response streaming is on by default for HttpClient in the browser |
Opt out per request if code reads the whole body synchronously |
| JSON Patch | Now based on System.Text.Json instead of Newtonsoft | Install the new package; avoid dynamic types like ExpandoObject
|
| EF Core 10 |
ExecuteUpdateAsync takes a regular lambda |
Rewrite hand-built expression trees as plain lambdas |
| EF Core 10 | EF tools need --framework on multi-targeted projects |
Add --framework net10.0 to dotnet ef commands while you multi-target |
| C# 14 |
field is a keyword inside property accessors |
Rename members called field or use @field
|
| C# 14 | Span overloads apply in more places | Fix new ambiguity errors with an explicit cast |
| Runtime | No default SIGTERM handler is installed | Add your own if you relied on it for graceful shutdown |
| Extensions |
BackgroundService runs all of ExecuteAsync as a Task |
Synchronous startup code in ExecuteAsync no longer blocks host startup |
| Containers | Default images use Ubuntu instead of Debian | Fix Dockerfiles that use Debian package names or paths |
CI/CD and Docker
The code is only half the upgrade; the pipeline still builds with whatever SDK it was told to use.
GitHub Actions:
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
Azure DevOps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '10.0.x'
Dockerfile: bump both stages and remember the new Ubuntu base:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
# ...
FROM mcr.microsoft.com/dotnet/aspnet:10.0
If your Dockerfile installs packages with apt-get, check the package names still exist on Ubuntu. In automated scripts, pass --interactive false to CLI commands, since the CLI now defaults to interactive mode for users.
Coming from .NET Framework
A .NET Framework 4.x app is a migration, not a version bump. .NET Framework 4.8 is not part of the November 2026 deadline, since its support follows the Windows lifecycle, but staying on it means no new runtime features and a shrinking library ecosystem.
What changes:
-
Project files. Convert old-style
.csprojfiles to SDK-style, andpackages.configtoPackageReference. -
Configuration.
web.config/app.configsettings move toappsettings.jsonand the options pattern. -
Hosting and startup.
Global.asaxandSystem.Webare gone; the pipeline is built inProgram.cswith middleware. - Dependency injection is built in, so third-party containers become optional.
- No direct path for some technologies. ASP.NET Web Forms, WCF server and Windows Workflow have no direct equivalent and need a partial rewrite (for example Razor Pages or Blazor for Web Forms, CoreWCF or gRPC for WCF).
The usual approach: move class libraries to .NET Standard 2.0 or multi-target them first, then migrate the web project, then remove the old one. For large apps, migrate incrementally route by route behind a reverse proxy instead of a big-bang rewrite.
The short checklist
- Inventory projects, pinned SDKs, Dockerfiles and pipelines
- Baseline test run on the current version
-
global.jsonpinned to the .NET 10 SDK - All projects on
net10.0, shared libraries first - Microsoft packages on 10.0.x, versions aligned
- New NuGet audit warnings reviewed
- Build clean with
-warnaserror - Breaking changes from .NET 9 and .NET 10 reviewed
- CI/CD and Docker images on 10.0
- Tests and integration tests green, compared to baseline
Free tool: scan your solution first
To get the inventory from the first step in one command, I wrote a free, open-source PowerShell script: NetUpgradeLab Scanner. It's read-only and produces a Markdown report of projects, outdated Microsoft packages, obsolete APIs and pinned SDK/Docker/CI versions.
pwsh ./Invoke-NetUpgradeScan.ps1 -Path C:\src\MySolution
Need a hand?
I'm Jasmin, a .NET developer with 6+ years of experience in C#, ASP.NET Core, Blazor and SQL Server. If you'd rather hand the upgrade off, I take on .NET 10 upgrades and .NET Framework migrations: Upgrade your app to .NET 10.
Sources
- .NET 8 and .NET 9 will reach End of Support on November 10, 2026 (Microsoft .NET Blog)
- Breaking changes in .NET 10 (Microsoft Learn)
- Breaking changes in ASP.NET Core 10 (Microsoft Learn)
- Breaking changes in EF Core 10 (Microsoft Learn)
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.