.NET 9.0 nuget hell guidance.
In our company we maintain an internal framework that targets the following: .NET Standard 2.0, .NET Core 3.1, .NET 6, .NET 7, .NET 8, and .NET 9.
With the release of .NET 9, we're now facing a serious case of NuGet dependency chaos—and we're looking for guidance.
What We're Seeing
🔄 Some Microsoft packages now publish up to version 9.X and claim compatibility with earlier frameworks like .NET Standard 2.0.
📌 Other packages require versioning that matches the target framework. For example:
If you're targeting .NET 6, you have to use version 6.X If you're targeting .NET 7, you need version 7.X
🤷♂️ Some packages behave inconsistently:
Some packages you can go all the way to version 8.X but not 9.X. The weird thing is the same packages on .NET 8 they can go to 9.X.
⚠️ Misleading compatibility + build-time warnings: Some packages claim support for earlier versions, but then generate warnings like:
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings> in the project file to ignore
this warning and attempt to run in this unsupported configuration at your own risk.
Downgrading to try to resolve these warnings often introduces other build or runtime failures.
Key Offender: System.Text.Json This is a primary example of the issue:
The latest versions claim support for earlier versions (like .NET Standard 2.0),
But at runtime, they can break in subtle or severe ways unless you're on the latest framework.
Older versions that work trigger “High Security Risk” warnings in NuGet, leaving us with no good option.
What We Need
We’d appreciate official guidance or clarification on:
- What the expected compatibility behavior should be across major package versions and TFMs.
- How to approach situations where compatibility is advertised but not functionally stable at runtime.
- How to balance runtime stability against NuGet security vulnerability warnings on older versions.
We need a clear strategy or official guidance on how to navigate this mess—ideally from Microsoft or someone who's managed to successfully tame this beast. At this point, we're dealing with a dependency matrix that’s becoming impossible to maintain.
Thanks in advance 🙏
Hello @maxpiva, thanks for reaching out and sharing your feedback.
I want to link to our Package Servicing Model document that establishes the high level principles around package versions and target frameworks in use.
It is important to underline that some of the runtimes that you listed are already out-of-support: .NET Core 3.1, .NET 6 and .NET 7. These won't get security fixes and shouldn't be used anymore. The NuGet security vulnerability warnings that get emitted for vulnerable packages are an additional data point why out-of-support runtimes and packages should be avoided.
Other packages require versioning that matches the target framework.
The document touches on that. The difference is that some packages are extensions of the framework, i.e. AspNetCore packages and only support the matching version of the framework while others like System.Text.Json are "broach reach ecosystem packages". I summarized that a while ago in another document. Here's an excerpt from that:
Misleading compatibility + build-time warnings:
The reason for this is because our packages support targeting .NET Standard >= 2.0. I definitely hear you on that! This is sub-optimal experience. We approached this problem a while ago but couldn't create momentum. Let me follow-up on that again.
My thinking is that we could add a NuGet feature that would allow to express unsupported target frameworks in a package. These TFMs would get flagged on the TFM support matrix that is rendered on nuget.org per package and would prevent installing on such TFMs (with an opt-out flag). That would better communicate the support matrix.
Would such a feature have helped in your case and avoided confusion around out-of-support runtimes? Please let me know if I didn't touch on any of your above points.
cc @richlander @ericstj
Thanks for the guidance, @ViktorHofer
Our main challenge is that we support both new and legacy codebases, and some of those still rely on older, unsupported .NET versions. I believe this is a common scenario across the industry, legacy systems are everywhere, but investing the time and money to fully modernize them is often a tough sell. 😉
Regarding the extra feature you mentioned, I think it should help. I agree that the issue mostly lies in supporting .NET Standard 1.0, 2.0, and 2.1, since unsupported .NET versions often fall back to .NET Standard when a specific version isn't available. So having something that clearly indicates, “no, you can use this in this version,” makes a lot of sense.
Ideally, the package manager would handle this more gracefully, perhaps something as simple as a [use-latest] or [use-preview], that intelligently resolves the best package version based on the targeted .NET versions. That would definitely make navigating and maintaining these compatibility hurdles much smoother.
EDIT: Post-thoughts.
use-latest keep me thinking, that pipelines are not fond of things that might change in the future.
Also, instead of specifying that as a version number Maybe an additional field like, autoresolve="true" which mean, use this version, on supported. NET Versions, but if your .NET Target doesn't support this version, resolve to the last one that is supported, for that specific target.
A Simple Example
- You create a
.NET 6console app. - You add
Microsoft.Extensions.Caching.Abstractionsusing the NuGet Package Manager. - The Package Manager suggests installing version 9.0.5, the latest stable release.
Upon building, you get this warning:
Microsoft.Extensions.Caching.Abstractions 9.0.5 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set <SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings> in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk.
When you check NuGet.org, you’ll find:
- Version 9.0.5 no longer supports .NET 6.
- It only targets .NET Standard 2.0 and .NET 8+.
- The last version that officially supports .NET 6 is 8.0.0.
Key Issues
- The Package Manager should recommend version 8.0.0 for .NET 6 and warn about 9.0.5 being unsupported.
- Update suggestions should be tailored to the active
TargetFramework. - NuGet Package Manager lacks proper handling for multi-targeted environments
The above leads to
- Confusion
- Risk of incompatible upgrades
- Broken builds with a single wrong update
Conclusion
This behavior is counterintuitive, misleading, and makes it easy to break apps unintentionally.
Proposed Solution
-
The NuGet Package Manager should support framework-aware targeting in multi-targeted projects, allowing users to select the active framework and receive relevant options for, search, update & consolidate.
-
It should always recommend the latest compatible version for the selected target framework not just the latest available version.
-
The Package Manager should warn clearly before installing unsupported versions. Relying solely on compiler warnings is insufficient.
-
<PackageReference>should support different versions per framework in multi-targeted projects.
This would improve clarity for developers and make it easier for the Package Manager to handle dependencies correctly.