Upgrading from .NET 8 to .NET 10: a practical guide

A step-by-step guide to moving a .NET 8 application to .NET 10 before 10 November 2026: breaking changes, packages, tests, hosting, rollback and AI help.

A lead developer with silver-blonde hair and glasses, in a navy roll-neck, works on a laptop with a plain lid at an oak desk in a converted barn office, with a mug and two closed navy notebooks beside her and flat fields through the windows

.NET 8 stops receiving security fixes on 10 November 2026, twelve days from now. If you run it in production, you probably have a list of applications, a limited number of working days and a nagging worry about the one nobody has touched since it was built. This guide is a sequence you can follow for each application, with realistic time-boxing and a way to record the position if a deadline slips.

It is the technical companion to our business explainer on what the 10 November end of support means. Everything here is as of 29 October 2026. Check the linked Microsoft pages for anything that matters to you, because they are updated.

Go straight to .NET 10

Microsoft's announcement of the end of support recommends upgrading to .NET 10, the current long-term support release, supported until 14 November 2028 according to the support policy. .NET 9 goes out of support on the same day as .NET 8, so it is not a useful stopping point; move from 8 to 10 in one step. The Learn page on upgrading to a new .NET version says the only required code change is the TargetFramework property, though in a real application there is more to check. You still cross two versions' worth of changes, so you read both breaking-change lists (step 2).

Step 1: inventory what you have

Before changing anything, find every project and where its version is set. Versions hide in three places:

  • global.json, which pins the SDK used to build
  • the TargetFramework in each .csproj
  • Directory.Build.props, which can set the framework for a whole folder of projects
# List installed SDKs and runtimes on this machine
dotnet --list-sdks
dotnet --list-runtimes

# Find every project and props file and the framework it sets
Get-ChildItem -Recurse -Include *.csproj,*.props |
  Select-String -Pattern "<TargetFrameworks?>"

Record each solution, its framework, how it is hosted, whether it has tests and who owns it. A spreadsheet is fine. Include class libraries and test projects. A net10.0 application can use a net8.0 library and runs it on .NET 10, so a library's target alone does not tie you to the old runtime; check that each library still works on .NET 10, and plan to retarget it when convenient. What does need .NET 8 installed is anything that runs on its own: applications, services, tools and test hosts still targeting net8.0. Those are the ones to move before support ends.

Step 2: read the breaking changes you are crossing

Microsoft lists changes by version and classifies each as binary incompatible, source incompatible or a behavioural change. Read both lists:

Both are grouped by area, such as ASP.NET Core, Entity Framework Core, core libraries, cryptography, serialization, SDK and MSBuild, and Windows Forms and WPF. You do not need to read all of it. Scan for the areas your application uses. Behavioural changes deserve the most attention, since the code still compiles and runs and can quietly do something different. For web applications, the ASP.NET Core page on migrating from .NET 9 to .NET 10 lists the project-file and package changes.

Step 3: update the SDK and the target framework

Work on a branch. Install the .NET 10 SDK, update global.json if you use one, and change the target.

{
  "sdk": {
    "version": "10.0.100",
    "rollForward": "latestFeature"
  }
}
<PropertyGroup>
  <TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

If many projects share a version, set it once in Directory.Build.props and remove the per-project values, so the next upgrade is a one-line change. Illustrative:

<Project>
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
  </PropertyGroup>
</Project>

Check the SDK version number against what you have installed. The values above are examples.

Step 4: update packages

Packages in the Microsoft.AspNetCore.*, Microsoft.EntityFrameworkCore.* and Microsoft.Extensions.* families should move to version 10.0.0 or later, as the ASP.NET Core migration page says. Then look at everything else.

dotnet list package --outdated
dotnet list package --deprecated
dotnet list package --vulnerable --include-transitive

The packages to worry about are those that are no longer maintained, or that have no release supporting .NET 10. For each one, choose between updating, replacing with a maintained alternative or isolating it behind an interface so it can be replaced later. Do not leave this to the end. A single abandoned dependency is the most common reason an upgrade takes weeks instead of days.

Step 5: build, then test

Build the solution and fix compiler errors first, then run the tests.

dotnet build --no-incremental
dotnet test

If there are no tests, stop and think. An upgrade without tests relies on someone clicking through the application and hoping they notice a difference. Writing characterisation tests around the paths that matter most, as described in adding tests to code nobody dares change, is often the best use of the first day or two, and the tests stay useful afterwards.

Pay attention to behavioural changes in the areas you identified in step 2: date and time handling, serialization settings, cryptography and anything involving encoding.

Step 6: runtime and hosting

An application that builds and passes tests on a laptop still has to run where it is hosted. Check each target:

  • IIS. Install the .NET 10 Hosting Bundle on the server. Microsoft's Hosting Bundle documentation says a manual IIS restart may be required afterwards, using net stop was /y and net start w3svc in an elevated shell. The ASP.NET Core Module is forward and backward compatible with in-support releases of .NET, so a rollback is possible while the older runtime is still installed.
  • Azure App Service. Check that .NET 10 is offered for your plan and operating system. The Learn page on configuring ASP.NET Core apps explains how to see the runtimes available and set the stack. App Service follows Microsoft's .NET dates: its language support policy says apps on an out-of-support runtime keep running, but get no security patches for it. We did not confirm .NET 10 availability for every plan type, so check yours.
  • Containers. Update the base images in your Dockerfiles, for example from the 8.0 tag to 10.0. The .NET 10 breaking-changes list notes that the default container images switch to Ubuntu, so check any commands in the image that assume a particular distribution.
  • Self-contained or desktop deployments. Rebuild and republish. Nothing on the target machine needs to be updated for a self-contained application, but it still needs re-testing.

Step 7: pipelines

Your build server needs the .NET 10 SDK, or your pipeline will fail or silently use the wrong one. Update agent images and setup steps. An illustrative GitHub Actions step:

- uses: actions/setup-dotnet@v5
  with:
    dotnet-version: 10.0.x

Check the action version against its current documentation. Pinning the SDK with global.json makes builds repeatable, and the runtime selection rules are in Microsoft's page on how .NET chooses versions.

Step 8: deploy to a test environment first, and plan the rollback

Deploy to an environment that mirrors production and run the checks that matter: sign-in, the main workflows, scheduled jobs, integrations and reports. Compare logs before and after for new warnings.

Decide the rollback before you deploy. For most applications that means keeping the previous build artefact and the older runtime installed until the new version has run for a few days, and knowing who can switch back and how long it takes. For database changes, take a backup and be clear about whether the schema change can be reversed.

Where AI tools help, and where a person must decide

Microsoft's porting overview currently recommends the GitHub Copilot upgrade agent (also called app modernization) for upgrades. It describes the .NET Upgrade Assistant as deprecated in its favour. The agent assesses a project, proposes a plan, makes changes and validates the build and tests, committing at each stage so you can review or roll back. We supply Microsoft licences and know these tools well, but other AI coding assistants can do similar work, and the right one depends on your team.

Whichever you use, treat the output as a pull request from a colleague you have not worked with before:

  • read the diff, especially changes to project files, configuration and anything touching security
  • rely on your tests, not on the tool's own report that it worked
  • never paste secrets or customer data into a prompt
  • check what your tool does with your code, and your data protection obligations

Our own method for AI-assisted changes is specification first, automated tests, independent review and a named engineer's sign-off, and it applies as well to an upgrade as to a new feature.

How long will it take?

These are our rule-of-thumb estimates, not measurements, and the variation between applications is large:

Application Typical effort
Small, well tested, current packages A day or two
Medium, some tests, a few old packages A week or two
Large, untested, or with abandoned dependencies Longer, and worth a short assessment first

With twelve days left, spend the first day on the inventory and the breaking-changes scan, then do the applications that are small and exposed first. Leave the awkward ones with a documented plan.

If the date slips

Some applications will not move by 10 November, and that is manageable if recorded. For each one, write down the reason, the risk you are carrying (no further security fixes for the runtime), any mitigating controls such as network restrictions, the owner and the date by which it will move. Review the entry on a fixed date. Our guide to what "out of support" means explains what an auditor or insurer will want to see.

A sensible first step

Today, run the project inventory from step 1 across every repository you own and count how many projects still target net8.0 or net9.0. That number tells you whether this is a day of work or a month of it, and it is the figure to take to your manager or client.

If you need more capacity than you have, software care covers .NET upgrades for systems that nobody in-house has time to look after, and Software & Integration covers building new applications on .NET 10.