.NET 5/6+ Migration Strategies for Your NuGet Package Libraries


Crista Perlton

Crista Perlton


Why You Should Create a Package Approval Workflow for  27th September, 2023

Do I really need to leave .NET Framework for .NET 8? 13th September, 2023


.NET 5/6+ Migration Strategies for Your NuGet Package Libraries

Posted on .

(This article was updated on November 17, 2021, to reflect .NET 6’s release.)

Choosing how—or even whether—to migrate your NuGet package libraries from .NET Framework to .NET 5/6+ depends on each application. Choose between five migration methods: abandonupdateforkmulti-target, or bridge.

Planning the migration of various .NET applications and NuGet libraries to .NET Core “vNext” (.NET 5/6+) is complicated. You likely have many applications and a lot of libraries, all in different lifecycle stages, ranging from ancient to still-being-planned. You can’t migrate your existing applications until you migrate your libraries.

But this presents a problem:

  • .NET 5/6+ applications cannot use .NET Framework libraries
  • .NET Framework applications cannot use .NET 5/6+ libraries

Therefore, how can you possibly migrate your libraries from .NET Framework to the new .NET?

There are five options for migrating your libraries to target a new .NET platform: abandonupdateforkmulti-target, or bridge.

In this article, we explain what each option entails, when you might want to choose it, and how to execute that option. We start with the simplest option but keep in mind that you must assess your applications, libraries, and migration plans to determine which option is best in each case.

Choice 1: Abandon

If you have no plan to ever move your library to .NET 5/6+, it will remain a .NET Framework library forever, receiving only small updates over the course of its lifetime.

WhenLibraries using deprecated technologies
ProNo extra/new work
Con The library will never be usable in .NET 5/6+ and will be only usable on an unsupported OS once the operating system goes out of support
HowContinue maintaining the library minimally and only as needed

When to Choose

“Abandon” is appropriate for a library that makes heavy use of technologies deprecated or not part of .NET 5/6+ (Web FormsWCF, and WF). There will be many applications and libraries at your organization that use “old” technology, but which will persist indefinitely without needing to be rewritten. Web Forms applications are a great example.


Perhaps you have a library called Kramerica.WCF.Utils that you use only in WCF-based applications. Since WCF will never be part of .NET 5/6+, there is no point in migrating that library. Just maintain Kramerica.WCF.Utils minimally and only as needed.

Choice 2: Update

“Updating” your libraries means migrating from .NET Framework to .NET 5/6+ while keeping some “room” in the version numbers for emergency releases.

WhenMost applications will use .NET 5/6+ but some old applications using .NET Framework endure
ProLeaves room to “fork after the fact” in emergencies (i.e., you can roll back to an older version)
ConMust maintain the original library until the new one is released
HowLeave room between the .NET Framework library’s last version number and the first .NET 5/6+ version number

When to Choose

If you’re going to be migrating ALL your applications in a short amount of time, it’s fine to update your old libraries and migrate to the new all at once. This option is also appropriate for libraries only being consumed by a very small number of applications.

How to Execute

Libraries are versioned. When you retarget, fix the code errors, and publish the “new” library, use a significantly higher major version number.

Using a big version bump (for example, Kramerica.Utils 2.6 up to Kramerica.Utils 5.0) communicates to consumers that there is a significant difference between the libraries. But perhaps more importantly, it provides enough versions between old and new to allow rollbacks. In an emergency situation, you can essentially go “back in time” and create a new version of an old library—essentially, you “fork after the fact.”


Kramerica.MVC.Utils uses MVC technology, which can be migrated to 5/6+. This library could be updated with minimal changes when migrated. When migrating, you version the “old” library Kramerica.MVC.Utils 3.1, and you version the “new” to Kramerica.MVC.Utils 5.0.

Choice 3: Fork  

Like choosing File > Save As on a Microsoft Word document before making changes, “forking” copies all the same source code into a separate repository. After copying, you can migrate in your libraries, target the new .NET platform, and you’ve got a whole new library without altering or removing the old one.

WhenFramework and 5/6+ applications that will coexist in the mid-to-long-term
ProThe new library and old library start the same but then continue independent of each other
ConMultiple, sometimes very similar codebases to maintain, release, and keep “in sync”
HowCopy the library, retarget, fix the code errors, and publish with a new name

When to Choose

If you’re going to need the .NET Framework version of your library for the mid-to-long term, you should fork. You may also consider this option if the migration will be complicated (as when parts of the .NET Framework in your library don’t exist in .NET 5/6+).

A guideline for forking is where 80-90% of the code will “overlap” but 10-20% are sufficiently different, it makes sense to fork. When this ratio is reversed or when the migration is trivial, forking will leave you with two, nearly identical codebases to maintain and release separately.

How to Execute

This is a relatively short, four-step process:

  1. Fork the current library.
    • Copy the source code and rename the project/repository similarly, such as Utils to UtilsCore.
  2. In the fork, change what Visual Studio will target.
    • If you tried to compile after this step, you would almost certainly get errors.
  3. Fix errors created by the retargeting and test.
    • Repeat this step until you are error-free.
  4. Publish the library with its new name.


Kramerica.Network.Utils is forked to create Kramerica.NetworkCore.Utils.

Choice 4: Multi-target   

Creating a single NuGet package library that contains both versions of your libraries (the .NET Framework version and the .NET 5/6+ version). This is very efficient because Visual Studio decides which .NET platform to target.

WhenEfficiently supporting multiple applications on different .NET platforms and keeping libraries in sync
ProOne library is usable in both .NET Framework and .NET 5/6+
ConMulti-targeted code is complicated to write and maintain
HowCreate one NuGet package with both (or more) libraries inside it

Consider movies as an analogy: If you buy the original Star Wars trilogy in hard copy, you’ll find a set of DVDs and Blu-ray discs in the same package, so you can play the film on whichever player you have at home. You have both choices at the same time, just like a multi-targeted NuGet package. (A note, though: while most Blu-ray players can now play DVDs, we have no evidence from Microsoft that .NET 5/6+ will ever be able to use Framework libraries.)

When to Choose

Creating a new application, you tell Visual Studio what .NET platform you’re targeting. If you’ve created a multi-targeted NuGet library, Visual Studio can select the right library from the different choices each time it compiles, saving you time.

Choose multi-targeting in situations where the .NET Framework library and the .NET 5/6+ library will be substantially similar, even if the “newer” library has different or additional functionality. (Blu-rays can do more than DVDs, but it’s still the same movie!) This is a great option if the codebase will remain mostly the same.

Be careful, though. There is a lot of information out there about multi-targeting, so it can be very hard to know whether you’re getting helpful advice.

How to Execute

When you compile C# code, you can pick what type of assembly you want, such as .NET Framework or .NET 5/6+. A NuGet package (zip file) has libraries under a subfolder named after the type of assembly. In this way, a NuGet package can have both a .NET Framework library (under the .net452 folder to specify version 4.5.2), or a .NET 5/6+ library (under the net5.0 folder).

The general concept of getting this to work is twofold:

  1. Configure your project to compile/build multiple times: once for each platform, you want to target (for example, .NET Framework 4.5.2 and .NET 5.0).
  2. Build a NuGet package out of all of those assemblies.

For detailed instructions, consult the documentation for Windows use or for Visual Studio for Mac.


Kramerica.Data.Models go from being a NuGet package that contains only a single Framework 4.8-compatible library to a package that contains multiple libraries, Kramerica.Data.FrameworkModels and Kramerica.Data.CoreModels.

Choice 5: Bridge

If you’re lucky and your library’s code just happens to be compatible with a now-deprecated technology called NET Standard 2.0, then you may be able to create a library that works in both .NET Framework and .NET 5/6+ without the complexity of multi-targeting.

WhenBuy time before making another choice (only if your code supports it)
ProOne library is usable in both .NET Framework and .NET 5/6+
ConAdopting a deprecated technology that will keep the library “locked” to .NET Framework’s functionality
HowChanging your library’s targeting to .NET Standard 2.0

.NET Standard was a predecessor to .NET Core and was Microsoft’s attempt to unify all the .NET platforms prior to .NET 5/6+. It’s a confusing technology, but the bottom line is that it may be a good choice if your libraries are already targeting.NET Framework 4.7.2 or later.

Continuing the Star Wars DVDs and Blu-rays in the same package analogy, targeting .NET Standard 2.0 is like releasing a single disc (let’s call it a “BluDVD”) that’s simultaneously a DVD and Blu-ray disc and can be played in most Blu-ray and DVD players.

When to Choose

This is a simpler but temporary alternative to multi-targeting. It only works if your library is currently targeting .NET Framework 4.7.2 or later. It is a way to buy time while you migrate your applications to .NET 5/6+. You will eventually need to settle on one of the other four choices for your libraries.

Instead of having a single NuGet package with two “substantially similar” libraries, this approach will yield a single library that is “locked” to whatever is available in .NET Framework 4.7.2. That might be okay, depending on the contents of your library.

With multi-targeting, you can introduce additional functionality in the .NET 5/6+ code for new applications. Over time, you have migrated all of your consuming applications to .NET 5/6+, you can simply remove the .NET Framework targeting from your library and return to a simple package. None of this is possible with the .NET Standard “bridge” approach.

How to Execute

This process is basically the same as “update,” though there is a higher chance for errors, which may be motivation to select a different method.

  1. In your library, change what Visual Studio will target to .NET Standard 2.0.
  2. Evaluate the errors and incompatibilities that Visual Studio reports.
    • Look for errors that will require substantial code changes
  3. Then, either…
    • Fix the errors (and test then repeat as needed) and publish the library with the new targeting
    • Choose another migration method

Related Questions with Resources

It’s easy to end up in a multi-targeting rabbit hole as you research. To save you time, we’ve answered many common questions with some good resources to check out.

What else is multi-targeting good for, besides a way to manage libraries for different platforms?

Multi-targeting is also a mindset for migrating applications. This is what we do with ProGet. You can build an application as .NET 5/6+ AND .NET Framework, then test these versions side-by-side. This lets you deploy the “newer”-platformed version to production, and if there’s a problem, quickly switch to the .NET Framework application. It’s like insurance.

What does multi-targeting look like “in real life”?

To see how to port from one library to another, check out Rick Strahl’s “Multi-targeting and Porting a .NET Library to .NET Core 2.0.” To learn about multi-targeted applications, read Brad Robinson’s “Non-Trivial Multi-Targeting with .NET.”

How can I target in SDK projects?

Microsoft gives us detailed documentation on SDK-style projects.

How do I develop for multiple platforms with .NET Framework?

It’s not terribly difficult, actually! But read Microsoft’s instructions to make sure you get it right.

Can I target multiple operating systems in one NuGet package?

This piece about .NET Standard is a bit dated but gives some instruction. .NET 5/6+ explicitly considers cross-platform development. This Microsoft documentation helps explain this, under the heading “When to Choose .NET 5/6+”

How does this relate to .NET Multi-Targeting Packs?

For the choices we discussed in this article, you do not need to worry about multi-targeting packs. But for those interested, this technical question is best answered by “additional reading” on what a multi-targeting pack even is and guidelines for use.

How does this relate to .NET Multi-platform App UI (MAUI)?

For the choices we discussed in this article, MAUI is unrelated. But for those interested, you can learn more about MAUI via Microsoft.

Hit the Right Target

.NET 5/6+ marks a new era in .NET development. But not all your applications and libraries will be immediately affected. Don’t rush headlong into migrating. Instead, make better decisions—and ultimately use fewer organizational resources—by assessing and planning which libraries should be abandoned, updated, forked, multi-targeted, or bridged.

Get a Copy of the .NET 5/6+ Migration Guide

The migration to .NET 5/6+ from .NET Framework has many complications and, as we’ve discussed, many options for how and when to migrate. We’ve built a guide on how to successfully migrate to .NET 5/6+ and beyond. Get your copy today!

Crista Perlton

Crista Perlton