.NET: specify constraints for NuGet package versions

A typical reference to a NuGet package in your project might look like

<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
Code language: HTML, XML (xml)

In the above example, we can see that we reference a package Newtonsoft.Json in a specific version, 11.0.1. We don’t specify any constraints for a person or a tool that would like to update the version in reference.

Now, let’s take a look how an IDE like Visual Studio will behave when we check if there are any updates to this package. As I write this, the NuGet server knows of the following versions of Newtonsoft.Json:

Exploring a list of all published package versions in NuGet.org service.

Default behavior: Visual Studio offers update to the latest stable package

Now, when a developer opens the “Manage NuGet Packages” window in Visual Studio and looks at outdated packages, she will be offered an upgrade to the most recent stable version:

Developer experience in Visual Studio 2022: the Manage NuGet packages window when constraints are not defined
Developer experience in Visual Studio 2022: the Manage NuGet packages window when we didn’t define version constraints

The policy to stay at the most recent stable version is often reasonable. I think it is a good default. Updating to the most recent version is something I typically perform without thinking. Other developers in the project might assume that too.

What’s more, the automated tooling for dependency updates (for example the Dependabot) will behave the same way. If that’s a good update policy for your particular dependency, everything is fine.

Adding NuGet version constraints

There are situations, where we might not want to update to the most recent version.

For example, I encountered a situation of a project in maintenance mode, where we would only want to update with the security patches, but avoid including any new features or including breaking changes. In that case, it translated to a versioning scheme in a way that we should only bump up the {patch} part in a {major}.{minor}.{patch} version.

Now, we could try to just remember about such rules, but this is a poor idea. Another person in the team might not know about the convention. We might forget, and Visual Studio will suggest us wrongly. Automatic tools like the mentioned Dependabot will not care about such convention unless we are explicit in defining constraints.

Luckily, the <PackageReference> allows defining constrains. For example, the following definition will only allow bumping the package to the most recent 12.*.* version because the end of the range is at 13.0.0 (exclusive):

<PackageReference Include="Newtonsoft.Json" Version="[11.0.1, 13.0.0)" />
Code language: HTML, XML (xml)

Visual Studio respects such constraints:

Developer's experience in Visual Studio when NuGet version constraints are defined for the package
Developer’s experience in Visual Studio after we defined NuGet version constraints for the package

Other IDEs and tools for bumping dependency versions should also respect that, as it is a part of the specification. See the linked document for more examples. And have fun bumping the packages! 🙂

Leave a Comment