andregoepel.dev
Start a conversation
All posts
.NET Modernization 6 min read

.NET 8 and .NET 9 End of Support: What to Do Before November 10, 2026

After November 10, 2026, .NET 8 and .NET 9 will no longer receive security patches. The migration target is already available: .NET 10 shipped as LTS in November 2025, with support through November 2028. This guide explains how to identify affected applications, review dependencies, and prioritize upgrades — including what to do when some services cannot meet the deadline.

.NET.NET 10MigrationLTS

What happens on November 10 — and what doesn't

First, the reassuring part: your applications will run on November 11 exactly as they did on November 9. There is no switch being flipped, no runtime that deactivates itself.

What changes is invisible — which is precisely why it matters: A final update may still be released on November 10 if there is a known critical issue. After that date, Microsoft stops shipping security updates for .NET 8 and .NET 9. Newly discovered vulnerabilities will no longer be addressed through Microsoft updates for these versions. Whether a particular application is affected then has to be assessed and, where necessary, mitigated separately. Since patches for newer versions are publicly documented, attackers may also gain clues about what to look for in older ones.

Why two versions at once?

This isn't an accident — it's Microsoft's release rhythm. A new .NET version ships every November: LTS (Long Term Support, 3 years) in odd years, STS (Standard Term Support, now 24 months) in even years. .NET 8 (LTS, November 2023) is reaching the end of its three years; .NET 9 (STS, November 2024) the end of its 24 months — both on November 10, 2026.

The consequence: unlike some earlier transitions, there is no "we're already on the newer version" this time. If you're on 8 or 9, you need to move to 10 — which has been available as LTS since November 2025 (supported through November 2028).

Why this is a business issue, not just an engineering one

"No more patches" sounds like a problem for the development team. In practice, it lands elsewhere:

Audits and certifications. Unsupported software in production is regularly scrutinized during audits and customer security assessments — especially when security updates are unavailable and there is no documented risk plan. "We didn't know" is the worst possible answer.

Customer contracts and supply chain. If you deliver or operate software for other businesses, you've likely made contractual commitments about security standards. And if you buy software, turn the question around: which of your vendors' products ship their own .NET 8 runtime — and what do those vendors say about November 10?

Am I affected? The 15-minute first check

The honest answer many teams give to "which of your services run on .NET 8 or 9?" is: "We'd have to check." That check is the first step — and it's small:

  1. Your own code: Search all repositories for net8.0 and net9.0 — not only in .csproj files, but also in centralized build files such as Directory.Build.props. Check global.json for pinned SDK versions as well.
  2. Servers, containers, and deployment artifacts: Run dotnet --list-runtimes on your hosts; inspect container base images and deployment manifests (e.g. for mcr.microsoft.com/dotnet/aspnet:8.0). Track self-contained deployments separately, because their runtime does not appear in the system-wide list.
  3. The forgotten corners: CI/CD agents, Windows services, internal tools, scheduled tasks — the little helpers that have been running unattended for years.
  4. Third-party software: Identify purchased products that ship their own .NET runtime and ask the vendors about their timeline. Those answers tend to take the longest — so ask early.

The result of this first check is a preliminary list: service, version, and criticality (externally reachable? customer data?). It provides the basis for a complete inventory and a rough effort estimate — turning a vague concern into a plannable work package.

The path to .NET 10 — realistic effort

The good news: moving from .NET 8 or 9 to .NET 10 is, in most cases, a moderate upgrade — not a large-scale migration. The typical sequence per service:

  1. Prepare development tools and build agents for the .NET 10 SDK; update pinned SDK versions in global.json
  2. Bump the target framework to net10.0
  3. Check NuGet packages and vendor SDKs for compatibility and update where needed
  4. Review breaking changes: when moving from 8 to 10, cover both .NET 9 and .NET 10, including the ASP.NET Core and EF Core components you use
  5. Run your tests, fix what surfaces
  6. Update CI/CD pipelines, hosting runtimes, and container base images; republish self-contained applications with an up-to-date runtime
  7. Deploy and observe

Microsoft documents the upgrade process and breaking changes for .NET 9 and .NET 10. Keeping .NET 10 patched remains part of routine operations after the upgrade.

With a well-tested codebase, an upgrade can be completed in a few days per service. Complex dependencies, outdated packages, or weak test coverage can push the effort significantly higher. The slowest dependency often determines the timeline: the NuGet package that doesn't support .NET 10 yet, or the vendor SDK whose maker is taking their time. That's why reviewing your package list belongs at the start of planning, not the end.

Two notes from practice:

Don't wait for it to "stabilize." .NET 10 has been available since November 2025 and has already received numerous monthly servicing updates. The phase where cautious teams wait for the first patch release is long over. "Let's wait and see" in this case means: running without security patches through the winter while the mature alternative sits ready.

Don't couple the upgrade with a rebuild. "While we're at it, let's modernize properly" sounds efficient — but it ties a hard security deadline to a project with an open end. Supported first, prettier second. Modernization deserves its own plan, with .NET 10 as a stable foundation.

If November 10 is no longer achievable

Sometimes the landscape is too big or a dependency too stubborn. Then the rule is: prioritize, don't resign.

Externally reachable services and anything holding customer data come first. For the rest: document the residual risk and put transitional measures in place — restrict reachability, segment the network, add protective layers in front. What matters is the character of these measures: a bridge with an end date, not a permanent state. A documented residual risk with a wind-down plan is at least traceable during audits and customer assessments; an unnoticed one is not.

Checklist

  • Inventory: all services, versions, criticality (this week)
  • Review dependencies: NuGet packages and vendor SDKs for .NET 10 status
  • Contact third-party software vendors
  • Set the order: externally reachable and customer-data services first
  • Run the upgrades: SDK, target framework, package compatibility, breaking changes, tests, hosting, pipelines, images
  • For stragglers: document residual risk, transitional measures with an end date
  • For 2027 and beyond: make runtime upgrades a fixed calendar item

Need a hand?

I've spent 15+ years helping companies modernize .NET landscapes — from taking stock to completed upgrades to architectures that turn the next end-of-support date into routine. Remote, predictable, no drama.

If you want to know what this could look like for your landscape: Book a free call → — 60 minutes about what you're working on and whether I can help. No sales pitch.

Get new posts by email

One mail per article. No newsletter theatre, no tracking pixels.

Unsubscribe with one click. Never shared.