Centralize NuGet package versions with Directory.Packages.props
Use NuGet Central Package Management to declare direct package versions once per repository instead of repeating them in every project file.
09 Aug 2025, 12:32 UTC

The problem: the same version declared in every project
In a solution with many .NET projects, each project file usually lists its own NuGet package versions. When a team upgrades Newtonsoft.Json, for example, someone must edit every project that references it. Missed edits leave projects on different versions, which causes inconsistent build output and runtime bugs that are hard to reproduce. Central Package Management (CPM) moves those direct versions into one file at the repository root.
Useful takeaway: enable CPM by adding Directory.Packages.props with ManagePackageVersionsCentrally set to true, then remove Version attributes from PackageReference items in individual projects. NuGet resolves the versions from the central file during restore.
How Central Package Management works
CPM is a NuGet and MSBuild feature. When the feature is enabled, MSBuild imports Directory.Packages.props before package restore. The file contains PackageVersion items that map package IDs to versions. Individual projects still use PackageReference, but they must omit the Version attribute for centrally managed packages. Transitive dependencies are still resolved by NuGet normally; CPM only centralizes the versions you declare directly.
Version assumption: CPM requires NuGet 6.2 or later and is stable in .NET SDK 7.0.100 or later. Older SDKs may ignore the central file or fail restore.
Worked configuration
Place this file at the repository root, next to the solution file:
true
In each project that consumes those packages, remove the Version attributes:
net8.0
If a project file still contains Version="..." on a centrally managed PackageReference, restore will fail. Remove every such attribute before enabling the feature.
Enable CPM and verify the result
- Back up the solution or commit the current state to version control.
- Add Directory.Packages.props to the repository root with ManagePackageVersionsCentrally set to true.
- Run the restore command from the repository root or solution directory:
dotnet restore
Where to run: a terminal at the repository root. Required permissions: read and write access to the project files and the local NuGet cache. Expected check: restore completes without errors related to missing or conflicting package versions. Risk: any PackageReference that still includes a Version attribute causes restore to fail.
- Inspect the resolved direct dependencies:
dotnet list package --include-transitive
Where to run: the solution directory. Expected check: the listed versions for Newtonsoft.Json and Microsoft.Extensions.Logging match Directory.Packages.props.
- Confirm the lock file and restore artifacts:
obj/project.assets.json
Open the generated assets file for each project and verify the resolved package versions match the central entries. packages.lock.json still records the resolved graph, but Directory.Packages.props is the authoritative source for the versions you declare directly.
Override a central version in one project
CPM supports VersionOverride on PackageReference. Use it when one project needs a newer version than the central file defines:
Only that project uses the overridden version; other projects continue to use the central version. Do not combine Version and VersionOverride on the same reference.
Limits and common mistakes
- Forgetting to remove Version attributes from project files causes restore errors.
- Placing Directory.Packages.props in a subdirectory instead of the repository root can prevent MSBuild from importing it for all projects.
- CPM does not change how NuGet resolves transitive dependencies; it only centralizes direct package versions.
- Floating versions such as 1.0.* are resolved at restore time and can reduce reproducibility.
- Large monorepos with many unused PackageVersion entries may increase restore time because NuGet still evaluates the central entries.
- Custom build logic that reads package versions from project files may break, because Directory.Packages.props is imported by NuGet MSBuild targets rather than the standard Microsoft.Common.props chain.
Rollback
Enabling CPM changes project files, so keep a rollback path: restore the Version attributes from the pre-CPM backup, remove or rename Directory.Packages.props, set ManagePackageVersionsCentrally to false or delete the property, then run dotnet restore again.
Practical check
After enabling CPM, run dotnet restore on a clean clone and compare the versions in obj/project.assets.json against Directory.Packages.props. If they match for every direct dependency, the central file is working as intended.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.