- 27 Feb 2023
- 4 Minutes to read
NuGet Package Versioning (SemVer2, Legacy)
- Updated on 27 Feb 2023
- 4 Minutes to read
All NuGet packages—whether hosted on NuGet.org or in your own ProGet repository—have version numbers like
6.2.0-beta1, etc. The format of these version numbers is called a version number scheme, and NuGet has had several different schemes over the years.
This article helps explain how ProGet interacts with the different types of NuGet package version numbers.
NuGet SemVer Package Versioning
Modern versions of ProGet (v5 and later) as well as NuGet (i.e. 4.3/2018+) support SemVer2 versioning for packages. This is a standardized versioning scheme across many packages and has become intuitive to many software developers. Use SemVer2-compatible versioning for your NuGet packages. We recommend it, Microsoft recommends it, and your future developers will appreciate it.
Use SemVer2-compatible versioning for your NuGet packages. We recommend it, Microsoft recommends it, and your future developers will appreciate it.
A version number in SemVer2 format consists of three integer parts (major, minor, and patch) plus an optional suffix pre-release. Each component has a specific meaning:
- Major: Breaking changes
- Minor: New features, but backward compatible
- Patch: Backward-compatible bug fixes
- Prerelease: A non-stable package such as alpha, beta, etc.
Example versions include:
See Microsoft's NuGet Package Versioning Documentation to learn more about how to use version numbers in your packages.
There is a fifth, rarely used component in SemVer2: the build metadata. It starts with a plus sign(
+) and may contain any of the characters that are allowed to contain suffixes for pre-release versions. Build metadata is ignored when comparing version numbers, so
1.2.3+bar are considered the same version.
In addition, NuGet generally ignores build metadata when it requests packages (e.g., if you specify It's not very useful in NuGet, causes confusion, and you can just add additional metadata to your .nuspec if you need it.
1.2.3+foo, NuGet only asks for
1.2.3); thus, ProGet generally doesn't require build metadata when it requests packages. We say "in general" because there are bugs and quirks in different versions of NuGet (and also of ProGet).
It's not very useful in NuGet, causes confusion, and you can just add additional metadata to your .nuspec if you need it.
Legacy NuGet Version Numbers
Prior to supporting SemVer2 versioning, NuGet used a 4-digit versioning scheme (e.g.
18.104.22.168) that is a combination of .NET's System.Version class and SemVer1 (an older, obsolete specification). This format isn't very well documented.
ProGet considers these "legacy version numbers" and defines them as:
- four decimal integers (digits
0-9), separated by periods (
- optionally a pre-release indicator, i.e. a hyphen (-) followed by a sequence of letters (a-z, A-Z), digits (0-9), and hyphens (-). Pre-release indicators must be at least one character long and begin with a letter.
Modern versions of ProGet and NuGet still fully support these types of version numbers.
Quirky Version Numbers
Ancient versions of NuGet (i.e. prior to 3.4/2016) had very few rules, and the rules changed from version to version of NuGet. Versions could be 1, 2, 3, or 4 parts. In addition, the equality rules were a bit strange. For example,
1.0.0 were considered different version numbers in most cases... except when they weren't. Likewise,
6.04 were almost always different versions, depending on how you requested them from NuGet.
We call these "quirky version numbers", and fortunately they have not been allowed on nuget.org since 2016. Unfortunately, there are many packages with "quirky version numbers" created before 2016 that people still want to use.
A great example of a quirky package is Owin. There's a single version (
1.0), and it hasn't changed since 2012. It's considered a "quirky version" becuase it's only a two-part number.
NuGet.org and Quirky Versions
It's not possible to upload packages in quirky versions to NuGet.org, but the old packages still exist.
NuGet.org now only shows a "normalized", three-part version number for quirky packages. Even if the package version (as specified in the nuspec file) is
1.0, NuGet.org will return
1.0.0 as the version number in the API.
You'll notice that
Owin is listed as
1.0.0, even though the actual version is
1.0. The only way to see the actual version is to download the file, and look in the
<metadata> <id>Owin</id> <version>1.0</version> ...snip... </metadata>
However, you still request
Owin-1.0 by name, directly. NuGet.org will return the one (and only) version of the
NuGet Client Support for Quirky Versions
Since not all NuGet servers behave like NuGet.org, the NuGet client (Visual Studio) has to do some interesting workarounds, including "version dancing", to make sure it can find a requested package.
For example, if a package has a dependency on
Owin-1.0, then you'll see NuGet make multiple requests to the package source: first
1.0.0, and then
1.0, and finally
This allows the NuGet client to work with both nuget.org, and legacy NuGet servers.
ProGet Support for Quirky Versions
You can still upload "quirky version" of packages to ProGet in many cases, and these quirky packages will work in most cases. However, they can cause headaches, especially when it comes to connectors and operations around local packages (like promotion and repackaging).
Owin will show up as
1.0.0 via a connector to NuGet.org, because that's what NuGet.org is reporting. In most cases, it will work just fine, even though it's really
1.0 behind the scenes.
However, when you pull
Owin to ProGet, ProGet will use the "true" version number (
1.0). It will also show
Old versions (before 5.3) had a "Legacy (Quirks) Nuget" feed that could handle all these oddities, but those feeds couldn't handle SemVer queries properly because queries like 1.0 were ambiguous (should 1.0 or 1.0.0 be returned, which are both valid versions, etc.), so it was a big compromise. They have been completely removed in ProGet 5.3.
Because there are very few packages with quirks like this, we recommend simply downloading the package, editing the
nuspec file, and replacing it with a semantic version.