10aday › tools

NuGet version range checker

Type the Version of a <PackageReference> such as [1.0,2.0), 1.*, 1.0.0-* or 1.0, and the versions published for that package. You see which versions match, in plain words, and which one dotnet restore will pick. The page runs a JavaScript copy of NuGet's own version code (NuGet.Versioning), checked against the real library and against real dotnet restore runs.

The surprise: NuGet picks the lowest match

npm, Cargo, pip and Maven take the highest version that matches a range. NuGet takes the lowest one (“lowest applicable version”). So [1.0,2.0) does not mean “the newest 1.x”: it means “1.0.0 if it exists”. For the newest 1.x, write a floating version: 1.*. We ran dotnet restore (.NET SDK 8.0.134, NuGet 6.8) against a local feed for each line below:

Version="…"Publisheddotnet restore gotWhy
[1.0,2.0)1.0.0, 1.5.0, 1.9.9, 2.0.01.0.0NuGet takes the lowest match, not the newest.
1.01.0.1, 1.2.0, 3.0.01.0.1 (NU1603)A bare version is a minimum. 1.0.0 is missing, so the next one up.
[1.0,2.0)1.5.0-beta, 1.6.0, 1.7.01.6.0 (NU1603)1.5.0-beta is skipped: no bound is a prerelease.
[1.0,2.0)1.5.0-betafails (NU1103)Only a prerelease matches: restore fails.
[1.0.0-beta,2.0)1.0.0-alpha, 1.0.0-beta, 1.6.01.0.0-betaA prerelease lower bound lets prereleases in.
(1.0,)1.0.0, 1.0.1, 5.0.01.0.1 (NU1604)Lowest version above 1.0.
(,2.0]0.1.0, 1.0.0, 2.0.00.1.0 (NU1604)No lower bound: the lowest version in the feed.
[1.0]1.0.1fails (NU1102)Exact version missing: restore fails.
*1.0.0, 2.0.0, 3.0.0-beta2.0.0Highest stable version.
*-*1.0.0, 2.0.0, 3.0.0-beta3.0.0-betaHighest version, prereleases included.
1.*0.9.0, 1.0.0, 1.4.0, 1.9.9-beta, 2.0.01.4.0Highest stable 1.x.
1.2.*1.1.0, 1.3.0, 1.4.01.3.0No 1.2.x at all: the lowest version above it.
1.*-*1.0.0, 1.5.0-beta, 1.5.0, 2.0.0-beta1.5.0Highest 1.x, prereleases allowed. 1.5.0 is higher than 1.5.0-beta.
1.0.0-beta*1.0.0-alpha, 1.0.0-beta.1, 1.0.0-beta.2, 1.0.0-rc.11.0.0-beta.2Highest 1.0.0 prerelease starting with beta.
[1.*,2.0)1.0.0, 1.5.0, 2.0.0, 2.1.01.5.0Floating inside a range: highest 1.x below 2.0.
^1.01.0.0failsNot NuGet syntax: rejected.
[1.0,2.0)0.9.0, 2.0.0fails (NU1102)Nothing between 1.0 and 2.0: restore fails.

Syntax cheat sheet

WriteMeansRestore picks (from 1.0.0, 1.2.0, 1.5.0-beta, 1.5.0, 2.0.0-rc.1, 2.0.0)

The last column is computed in your browser by the same engine as the checker above.

How NuGet orders versions

A NuGet version has 3 or 4 numbers (1.2.3.4; missing ones are 0, so 1.0 = 1.0.0 = 1.0.0.0), then an optional prerelease label after - and optional build metadata after +. A prerelease is lower than the same version without label: 2.0.0-rc.1 < 2.0.0. Labels are compared part by part (split at dots): numbers as numbers (beta.2 < beta.10), words alphabetically and case-insensitively (RC = rc, unlike npm). Build metadata is ignored.

For Go programs: the same rules as a library, github.com/Lawatch/10aday/verrange/nuget (open source, no dependencies, tested against NuGet.Versioning and real dotnet restore).

From a terminal, with Go installed: go run github.com/Lawatch/10aday/verrange/cmd/verrange@latest nuget "[1.0,2.0)" 1.0.0 1.9.9 2.0.0 prints yes or no for each version, then the one the tool would pick (command docs).

Related: Maven version range checker (same bracket syntax, but Maven takes the highest match) and Gradle dynamic version checker (1.+, ranges, latest.release). For npm, Cargo, Composer, pip and RubyGems, use the Version Constraint Checker; to sort versions, the Version sorter; for betas and release candidates, what each package manager installs when a beta is out.

FAQ

Why does NuGet install 1.0.0 for [1.0,2.0) and not the newest 1.x?

NuGet uses the lowest applicable version: in a range it picks the lowest version that matches, unlike npm, Cargo or Maven, which pick the highest. We ran dotnet restore with 1.0.0, 1.5.0, 1.9.9 and 2.0.0 published: [1.0,2.0) restored 1.0.0. To get the newest 1.x, use a floating version: 1.* restored 1.4.0 out of 0.9.0, 1.0.0, 1.4.0, 1.9.9-beta and 2.0.0.

Does Version="1.0" mean exactly 1.0 in a PackageReference?

No. A bare version means 1.0 or higher. NuGet takes 1.0.0 if it exists. If it does not, it takes the next higher version and prints warning NU1603. For exactly 1.0, write [1.0]: if 1.0 is missing, restore fails with NU1102.

Why does NuGet skip my prerelease package?

In a normal range, prerelease versions are only used if one of the bounds is itself a prerelease, or with a floating version ending in -*. [1.0,2.0) with 1.5.0-beta and 1.6.0 published restored 1.6.0. With only 1.5.0-beta published it failed with NU1103. [1.0.0-beta,2.0) or 1.*-* let prereleases in.

What is the difference between 1.*, 1.*-* and *-*?

1.* takes the highest stable 1.x version. 1.*-* takes the highest 1.x version, prereleases included. *-* takes the highest version of all, prereleases included. * takes the highest stable version.

Can I use ^1.0, ~1.0 or >=1.0 in NuGet?

No. These are npm or Cargo notations. NuGet only understands a bare version (a minimum), brackets such as [1.0,2.0) and floating versions with *. dotnet restore rejects ^1.0, ~1.0 and >=1.0. The NuGet equivalent of ^1.2 is [1.2,2.0), but NuGet will still pick the lowest match.

What do warnings NU1603 and NU1604 mean?

NU1603: the lower bound of your range was not found, so NuGet used the next version up. NU1604: the range has no included lower bound, such as (,2.0] or (1.0,): the result depends on what the feed holds. (,2.0] restored 0.1.0, the lowest version available.

Sources