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 Directory.Packages.props
file.
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 ManagePackageVersionsCentrally
to true
.
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
The 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.props
file in theRepository\Solution1\
directory. - Project2 will evaluate the
Directory.Packages.props
file in theRepository\
directory.
Get started
To fully onboard your repository, consider taking these steps:
- Create a new file at the root of your repository named
Directory.Packages.props
that declares your centrally defined package versions in. - Declare
<PackageVersion />
items in yourDirectory.Packages.props
. - Declare
<PackageReference />
items withoutVersion
attributes in your project files.
Transitive pinning
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 CentralPackageTransitivePinningEnabled
to true
in a project or in a Directory.Packages.props
or 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 CentralPackageVersionOverrideEnabled
to false
in a project or in a Directory.Packages.props
or 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 ManagePackageVersionsCentrally
to false
:
<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.
Closing
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.
Feedback
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.
Is there a reason to go with this over the CentralPackageVersions SDK? As far as I can tell the only difference is the automatic transitive dependency logic (which, to be fair, is pretty nice).
For anyone who’s interested, I knocked up a tool that converts a solution (or project) to/from centralised package management.
https://github.com/Webreaper/CentralisedPackageConverter
Can transitive pinning be used to replace packages.lock.json?
Visual Studio 2022 17.2.5, dotnet SDK 6.0.301, still getting “The project CentralPackageVersions.csproj is using CentralPackageVersionManagement, a NuGet preview feature.”
Why are floating package versions not allowed?
Is this feature still in Preview? The output from a build/restore in Visual studio suggests so.
Is it possible to “Include” an entire ItemGroup somehow instead of having to declare the packagereferences one by one?
For instance, in my Directory.packages.props I’d like to label different ItemGroups depending on where in my project I will use them.
A feature I’m missing is that if you try to update the nuget packages with Visual Studio nuget package management dialog, it adds the Version=”1.2.3″ to the PackageReference items, instead of updating the PackageVersion items in the Directory.Packages.props
In other words, if someone chooses to use Directory.Packages.props, you can’t use package management dialog any longer.
I love this feature! We've been doing something similar by making variables with versions in the Build.props file and only using the variables in the csproj files. Which has worked, but doesn't work with tooling (like dependabot).
I tried this out yesterday with VS 2022 17.2 and it wasn't working. I also tried at the command line too (with SDK 6.0.300). It doesn't seem to be working for me. Was this actually part...
https://gist.github.com/axelheer/da455edebbd64f6c20bce962542d06bb
I just wrote a simple script to generate the packages file based on all project files and the like. Maybe it helps someone until there is proper tooling support for this… 😅
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.