Introducing Central Package Management
Central Package Management
Dependency management is a core feature of NuGet. Managing dependencies for a single project can be easy. Managing dependencies for multi-project solutions can prove to be difficult as they start to scale in size and complexity. In situations where you manage common dependencies for many different projects, you can leverage NuGet’s central package management features to do all of this from the ease of a single location.
Historically, NuGet package dependencies have been managed in two main locations:
packages.config– An XML file used in older project types to maintain the list of packages referenced by the project.
<PackageReference />– An XML element used in new project types that manages NuGet dependencies directly within project files.
Starting with NuGet 6.2, you can centrally manage your dependencies in your projects with the addition of a
The feature is available across all NuGet integrated tooling.
- Visual Studio 2022 17.2 and later
- .NET SDK 6.0.300 and later
- .NET SDK 7.0.0-preview.4 and later
- nuget.exe 6.2.0 and later
Older tooling will ignore Central Package Management configurations and features. To use this feature to the fullest extent, ensure all your build environments use the latest compatible tooling versions.
Central Package Management will apply to all
<PackageReference> projects – including legacy .csproj – as long as compatible tooling is used.
Enabling Central Package Management
To get started with central package management, you can create a
Directory.Packages.props file at the root of your solution and set the MSBuild property
Inside, you can define each of the respective package versions required of your solution using
<PackageVersion /> elements that define the package ID and version.
<Project> <PropertyGroup> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> </PropertyGroup> <ItemGroup> <PackageVersion Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup> </Project>
Within a project of the solution, you can then use the respective
<PackageReference /> syntax you know and love, but without a
Version attribute to infer the centrally managed version instead.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" /> </ItemGroup> </Project>
Now you’re using central package management and managing your versions in a central location!
Central Package Management rules
Directory.Packages.props file has a number of rules with regards to where it’s located in a repository’s directory and its context. For the sake of simplicity, only one
Directory.Packages.props file is evaluated for a given project.
What this means is that if you had multiple
Directory.Packages.props files in your repository, the file that is closest to your project’s directory will be evaluated for it. This allows you extra control at various levels of your repository.
Here’s an example, consider the following repository structure:
Repository |-- Directory.Packages.props |-- Solution1 |-- Directory.Packages.props |-- Project1 |-- Solution2 |-- Project2
- Project1 will evaluate the
Directory.Packages.propsfile in the
- Project2 will evaluate the
Directory.Packages.propsfile in the
To fully onboard your repository, consider taking these steps:
- Create a new file at the root of your repository named
Directory.Packages.propsthat declares your centrally defined package versions in.
<PackageVersion />items in your
<PackageReference />items without
Versionattributes in your project files.
You can automatically override a transitive package version even without an explicit top-level
<PackageReference /> by opting into a feature known as transitive pinning. This promotes a transitive dependency to a top-level dependency implicitly on your behalf when necessary.
You can enable this feature by setting the MSBuild property
true in a project or in a
Directory.Build.props import file:
<PropertyGroup> <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled> </PropertyGroup>
Overriding package versions
You can override an individual package version by using the
VersionOverride property on a
<PackageReference /> item. This overrides any
<PackageVersion /> defined centrally.
<Project> <ItemGroup> <PackageVersion Include="PackageA" Version="1.0.0" /> <PackageVersion Include="PackageB" Version="2.0.0" /> </ItemGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="PackageA" VersionOverride="3.0.0" /> </ItemGroup> </Project>
You can disable this feature by setting the MSBuild property
false in a project or in a
Directory.Build.props import file:
<PropertyGroup> <CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled> </PropertyGroup>
When this feature is disabled, specifying a
VersionOverride on any
<PackageReference /> item will result in an error at restore time indicating that the feature is disabled.
Disabling Central Package Management
If you’d like to disable central package management for any reason, you can disable this feature by setting the MSBuild property
<PropertyGroup> <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally> </PropertyGroup>
Warning when using multiple package sources
When using central package management, you will see a
NU1507 warning if you have more than one package source defined in your configuration. To resolve this warning, map your package sources with package source mapping or specify a single package source.
There are 3 package sources defined in your configuration. When using central package management, please map your package sources with package source mapping (https://aka.ms/nuget-package-source-mapping) or specify a single package source.
We hope that these features will help improve your productivity of managing your dependencies as they scale with your projects, promote healthy security best practices, and empower your team to achieve more with the ease of a single location. There is currently no support in Visual Studio or the .NET CLI for Central Package Management.
This feature is considered in preview and is under active development. Your feedback is important to us. If there are any problems with this feature, check our GitHub Issues. For new issues within this experience, please report a GitHub Issue. To help us with documentation, please feel free to contribute and ask questions on how we can explain the feature further.
Fun fact: It’s already supported by GitHub’s Dependabot too!
Very very cool. I am really digging all the consistent and positively-aligned “*Enabled” property names/settings. I hate having to disable something with a true (or enable something with a false), and I know I am not the only one. Nice work over there. 🙂
It seems nuget 6.2 and visual studio 2022 17.2 are not released yet?
Is this supported in the latest 17.2 preview? (I can’t find it in the 17.2 preview release notes)
Visual Studio 17.2 Preview 3 was just released yesterday which includes support. Sadly we are not included in the release notes, but I’ll see if we can fix that.
NuGet 6.2 will come out as a preview relatively soon for standalone support. Similar with .NET 6 SDK. Today you can use VS to preview and in the near future the standalone CLI tooling.
Hey, I’m just trying to figure out the status of support in the dotnet SDK 6.0.300 and VS 17.2, it’s still reporting as a preview feature on the command line, and adding packages doesn’t seem to work.
Have I got it wrong, or is it landing in later releases?
I really like the feature in general as it will allow us to better ensure version consistency for packages across the solution, reducing the chance that someone updates a package in one project and not in others which sometimes results in nasty runtime issues.
I was a bit surprised however by the introduction of a brand new file specifically for this: the
Directory.Packages.propsfile. I assumed that, since these are all MSBuild extension files, that one would be able to just add whatever new elements are needed (like
Directory.Build.propsand this would result in the same functionality. Is that not the case? Would adding
Directory.Build.propsresult in incorrect behavior?
Could you elaborate on the decision to create a new file instead of leveraging
Due to the order of MSBuild evaluations where properties are evaluated first including all imports, items are evaluated second, it is necessary for NuGet to control when the package versions are included. The easiest way to accomplish this is to have a new file that NuGet imports at the correct time. It also means that the Directory.Packages.props file contains just package version information and isn’t cluttered with other build logic which might be desirable for larger repositories. However, since it is just MSBuild, you can declare PackageVersion items anywhere. Just keep in mind that doing so may or may not be supported.
Fair enough, I appreciate the clarification.
Is there a way to override the location of Directory.Packages.props?
On another note, it feels like this could open the door for “solution-level” packages at some point: a way to have functionality that is not project-specific but is considered for the solution as a whole (say, “adding a
Company.StandardsNuGet package that automatically adds an
.editorconfigfile to the solution”).
Is the team considering adding solution-level package support in the near future to allow for such “higher-level” sharing scenarios?
I think you’re onto something! This is the third time I’ve heard this in the last couple days alone!
Something like that would help so much it’s not even funny.
With the recent architectures that rely on several microservices and smaller projects, it is extremely usual to have many small repositories that are handled independently. However, in this scenario, it is a huge pain to keep all projects in a company (or even a larger team) in sync when it comes to things like
Having a simplified way to share all/some of these across multiple repositories in a team or even a whole company would be insanely valuable. Today, I’m basically forced to copy/paste all the files in each and every repository, which is not very fun from a maintenance perspective.
If there was a way to have these be “installed” by a so-called “solution-level NuGet package”, we could much more easily manage updates and discoverability of changes by pushing a new version of the package that then each repo updates (it would show as an “out of date package” in package explorer). That, and creating a new repo would be reduced to referencing the 1/handful of company standards packages.
The NuGet 6.2 link in this post is wrong.
Thank you. It’s a placeholder for when the release notes go live. I can remove that for now.
Will Azure DevOps build agents automatically support this functionality?
Yes, it will require the respective dotnet or NuGet CLI versions installed. That may take a couple months for those images to be updated and given it may take another release cycle to get the CLI components since only VS support is officially out.
Sounds good. Is there/will there be UI support for this in VS?
Yes, much will come from new project system support and enhancements to the package manager UI. We will likely share our plans on GitHub for upcoming releases in the near future.
How does this interact with locked mode? Does it use a central lock file?
Very nice! I like it. Concerning the post above:
Which file(s) would this be added to?
Central package management is off by default but you can add the ManagePackageVersionsCentrally property to any project or common import like Directory.Build.props.