Central Package Management in .NET: A Must-Have for Scalable Projects

Central Package Management in .NET A Must-Have for Scalable Projects

Working with multiple projects in a .NET solution often leads to one common issue…

Managing package versions across the entire codebase.

Central Package Management (CPM) solves this by allowing you to define package versions in a single, centralized file: Directory.Packages.props. From that point on, all projects inherit their versions automatically, no duplication, no drift.

 

What Central Package Management is and how it works under the hood

One of the most common problems in multi-project .NET solutions is version drift. Each project typically defines its own NuGet dependencies with individual version numbers. Over time, this leads to duplicated version declarations, inconsistencies, and unexpected bugs, especially when different projects rely on slightly different versions of the same package.

Example:

  • Project 1 uses MassTransit Version=”8.5.0″
  • Project 2 uses MassTransit Version=”8.2.0″

 

Central Package Management (CPM) is a feature provided by the .NET SDK that allows you to manage NuGet package versions in a single location for all projects in your solution. Instead of duplicating <PackageReference> versions across multiple .csproj files, you define them once in a Directory.Packages.props file placed at the root of your repository.

How it works…

You define the versions centrally
Create a file Directory.Packages.props, where you specify only the versions, and enable ManagePackageVersionsCentrally:

C#
				<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>

  <ItemGroup>
    <PackageVersion Include="FluentValidation" Version="11.8.3" />
    <PackageVersion Include="MediatR" Version="12.0.1" />
  </ItemGroup>
</Project>
			

You reference the packages without versions in each project Your .csproj files stay clean and minimal:

C#
				<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
     <PackageReference Include="FluentValidation" />
     <PackageReference Include="MediatR" />
  </ItemGroup>

</Project>
			

MSBuild handles the version resolution during restore
When you run dotnet restore or build the solution, MSBuild scans the directory tree, finds the central file, and injects the correct versions.

But what if I need a different version in one of the projects?

Central Package Management defines the default version for each package, but it doesn’t remove your ability to override it when needed.

If a specific project requires a different version of a package, you can still define the version locally inside that project’s .csproj file. When you do this, the local version takes precedence over the one defined in Directory.Packages.props.

Here’s what that looks like:

 

C#
				<ItemGroup>
  <PackageReference Include="FluentValidation" VersionOverride="11.6.0" />
</ItemGroup>
			

In this case, even if the central file defines FluentValidation as 11.8.3, this particular project will use 11.6.0.

This is useful in scenarios like:

  • A legacy project that hasn’t been updated to the latest version yet

  • A migration in progress where different modules need different versions temporarily

  • Testing compatibility of a new package version in isolation

This flexibility is powerful, but it comes with responsibility. Overriding versions should be intentional and well-documented. If you start scattering custom versions across projects, you lose the main benefit of CPM: consistency.

Installing a package globally in all projects

If you want a package to be included by default in every project, without having to add manually, you can use the GlobalPackageReference element inside the Directory.Packages.props file.

Examples:

C#
				<Project>
  <ItemGroup>
    <PackageVersion Include="FluentValidation" Version="11.8.3" />
    <GlobalPackageReference Include="FluentValidation" />
  </ItemGroup>
</Project>

			
C#
				<ItemGroup>
  <GlobalPackageReference Include="FluentValidation" Version="11.8.3" />
</ItemGroup>
			

This is useful for utility libraries, analyzers, or any package you want applied across the entire solution without repeating yourself.

With Central Package Management:

  • You define package versions in one place.

  • You avoid conflicts across projects.

  • You simplify upgrades.

  • You reduce noise in .csproj files.

  • You make builds more predictable.

Conclusion

Central Package Management solves a real problem. It reduces friction, improves consistency, and simplifies version control across large solutions.

It’s native to the .NET SDK, easy to adopt, and requires minimal setup.

If you’re managing multiple projects and still defining versions in every .csproj, you’re doing unnecessary work. Switch to CPM, and don’t look back.

Thank you for reading.

See you next time!

Share the Post:
plugins premium WordPress