NuGet Package Management When to Use This Skill Use this skill when: Adding, removing, or updating NuGet packages Setting up Central Package Management (CPM) for a solution Managing package versions across multiple projects Troubleshooting package conflicts or restore issues Golden Rule: Never Edit XML Directly Always use dotnet CLI commands to manage packages. Never manually edit .csproj or Directory.Packages.props files.
DO: Use CLI commands
dotnet add package Newtonsoft.Json dotnet remove package Newtonsoft.Json dotnet list package --outdated
DON'T: Edit XML directly
Why: CLI validates package exists and resolves correct version Handles transitive dependencies correctly Updates lock files if present Avoids typos and malformed XML Works correctly with CPM Central Package Management (CPM) CPM centralizes all package versions in one file, eliminating version conflicts across projects. Enable CPM Create Directory.Packages.props in solution root: < Project
< PropertyGroup
< ManagePackageVersionsCentrally
true </ ManagePackageVersionsCentrally
</ PropertyGroup
< ItemGroup
< PackageVersion Include = " Newtonsoft.Json " Version = " 13.0.3 " /> < PackageVersion Include = " Serilog " Version = " 4.0.0 " /> < PackageVersion Include = " xunit " Version = " 2.9.2 " /> </ ItemGroup
</ Project
Project Files with CPM Projects reference packages without versions :
< Project Sdk = " Microsoft.NET.Sdk "
< ItemGroup
< PackageReference Include = " Newtonsoft.Json " /> < PackageReference Include = " Serilog " /> </ ItemGroup
</ Project
Adding Packages with CPM
Adds to Directory.Packages.props AND project file
dotnet add package Serilog.Sinks.Console
Result in Directory.Packages.props:
Result in project file:
Shared Version Variables Group related packages with shared version variables: < Project
< PropertyGroup
< ManagePackageVersionsCentrally
true </ ManagePackageVersionsCentrally
</ PropertyGroup
< PropertyGroup Label = " SharedVersions "
< AkkaVersion
1.5.59 </ AkkaVersion
< AkkaHostingVersion
1.5.59 </ AkkaHostingVersion
< AspireVersion
9.0.0 </ AspireVersion
< OpenTelemetryVersion
1.11.0 </ OpenTelemetryVersion
< XunitVersion
2.9.2 </ XunitVersion
</ PropertyGroup
< ItemGroup Label = " Akka.NET "
< PackageVersion Include = " Akka " Version = " $(AkkaVersion) " /> < PackageVersion Include = " Akka.Cluster " Version = " $(AkkaVersion) " /> < PackageVersion Include = " Akka.Cluster.Sharding " Version = " $(AkkaVersion) " /> < PackageVersion Include = " Akka.Cluster.Tools " Version = " $(AkkaVersion) " /> < PackageVersion Include = " Akka.Persistence " Version = " $(AkkaVersion) " /> < PackageVersion Include = " Akka.Streams " Version = " $(AkkaVersion) " /> < PackageVersion Include = " Akka.Hosting " Version = " $(AkkaHostingVersion) " /> < PackageVersion Include = " Akka.Cluster.Hosting " Version = " $(AkkaHostingVersion) " /> </ ItemGroup
< ItemGroup Label = " Aspire "
< PackageVersion Include = " Aspire.Hosting " Version = " $(AspireVersion) " /> < PackageVersion Include = " Aspire.Hosting.AppHost " Version = " $(AspireVersion) " /> < PackageVersion Include = " Aspire.Hosting.PostgreSQL " Version = " $(AspireVersion) " /> < PackageVersion Include = " Aspire.Hosting.Testing " Version = " $(AspireVersion) " /> </ ItemGroup
< ItemGroup Label = " OpenTelemetry "
< PackageVersion Include = " OpenTelemetry.Exporter.OpenTelemetryProtocol " Version = " $(OpenTelemetryVersion) " /> < PackageVersion Include = " OpenTelemetry.Extensions.Hosting " Version = " $(OpenTelemetryVersion) " /> < PackageVersion Include = " OpenTelemetry.Instrumentation.AspNetCore " Version = " $(OpenTelemetryVersion) " /> < PackageVersion Include = " OpenTelemetry.Instrumentation.Http " Version = " $(OpenTelemetryVersion) " /> </ ItemGroup
- <
- ItemGroup
- Label
- =
- "
- Testing
- "
- >
- <
- PackageVersion
- Include
- =
- "
- xunit
- "
- Version
- =
- "
- $(XunitVersion)
- "
- />
- <
- PackageVersion
- Include
- =
- "
- xunit.runner.visualstudio
- "
- Version
- =
- "
- $(XunitVersion)
- "
- />
- <
- PackageVersion
- Include
- =
- "
- FluentAssertions
- "
- Version
- =
- "
- 6.12.0
- "
- />
- <
- PackageVersion
- Include
- =
- "
- Verify.Xunit
- "
- Version
- =
- "
- 26.0.0
- "
- />
- </
- ItemGroup
- >
- </
- Project
- >
- Benefits:
- Update all Akka packages by changing one variable
- Clear organization with labeled ItemGroups
- Prevents version mismatches in related packages
- When NOT to Use CPM
- Central Package Management isn't always the right choice:
- Legacy Projects
- Migrating an existing large solution to CPM can introduce issues:
- Existing version conflicts become visible all at once
- Some packages may have intentional version differences
- Migration requires touching many files simultaneously
- Recommendation
- For legacy projects, migrate incrementally or stick with per-project versioning if it's working. Version Ranges CPM requires exact versions - it doesn't support version ranges:
< PackageVersion Include = " Newtonsoft.Json " Version = " [13.0,14.0) " />
< PackageVersion Include = " Newtonsoft.Json " Version = " 13.0.3 " /> If you need version ranges (rare, but some library scenarios require it), CPM won't work. Older .NET Versions CPM requires: .NET SDK 6.0.300+ or later NuGet 6.2+ or later Visual Studio 2022 17.2+ or later If you're targeting older SDK versions or have team members on older tooling, CPM may cause build failures. Multi-Repo Solutions If your solution spans multiple repositories that are built independently, CPM's single Directory.Packages.props won't help - each repo needs its own. CLI Command Reference Adding Packages
Add latest stable version
dotnet add package Serilog
Add specific version
dotnet add package Serilog --version 4.0 .0
Add prerelease
dotnet add package Serilog --prerelease
Add to specific project
dotnet add src/MyApp/MyApp.csproj package Serilog Removing Packages
Remove from current project
dotnet remove package Serilog
Remove from specific project
dotnet remove src/MyApp/MyApp.csproj package Serilog Listing Packages
List all packages in solution
dotnet list package
Show outdated packages
dotnet list package --outdated
Include transitive dependencies
dotnet list package --include-transitive
Show vulnerable packages
dotnet list package --vulnerable
Show deprecated packages
dotnet list package --deprecated Updating Packages
With CPM: Edit the version in Directory.Packages.props
Then restore to apply
dotnet restore
Without CPM: Remove and add with new version
dotnet remove package Serilog dotnet add package Serilog --version 4.1 .0
Or use dotnet-outdated tool (recommended)
dotnet tool install --global dotnet-outdated-tool dotnet outdated --upgrade Restore and Clean
Restore packages
dotnet restore
Clear local cache (troubleshooting)
dotnet nuget locals all --clear
Force restore (ignore cache)
dotnet restore --force Package Sources List Sources dotnet nuget list source Add Private Feed
Add authenticated feed
dotnet nuget add source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \ --name MyFeed \ --username az \ --password $PAT \ --store-password-in-clear-text NuGet.config For solution-specific sources, create NuGet.config :
< configuration
< packageSources
< clear /> < add key = " nuget.org " value = " https://api.nuget.org/v3/index.json " /> < add key = " MyPrivateFeed " value = " https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json " /> </ packageSources
< packageSourceCredentials
< MyPrivateFeed
< add key = " Username " value = " az " /> < add key = " ClearTextPassword " value = " %NUGET_PAT% " /> </ MyPrivateFeed
</ packageSourceCredentials
</ configuration
Common Patterns Development-Only Packages
< PackageVersion Include = " Microsoft.SourceLink.GitHub " Version = " 8.0.0 " />
< PackageReference Include = " Microsoft.SourceLink.GitHub " PrivateAssets = " All " /> Conditional Packages
< ItemGroup Condition = " ' $(Configuration)' == 'Debug' "
< PackageReference Include = " JetBrains.Annotations " /> </ ItemGroup
< ItemGroup Condition = " ' $(TargetFramework)' == 'net8.0' "
< PackageReference Include = " System.Text.Json " /> </ ItemGroup
Version Override (Escape Hatch) When you must override CPM for one project (rare):
- <
- PackageReference
- Include
- =
- "
- Newtonsoft.Json
- "
- VersionOverride
- =
- "
- 12.0.3
- "
- />
- Warning
- This is detected by Slopwatch (see dotnet/slopwatch skill) as potential slop. Troubleshooting Version Conflicts
See full dependency tree
dotnet list package --include-transitive
Find what's pulling in a specific package
dotnet list package --include-transitive | grep -i "PackageName" Restore Failures
Clear all caches
dotnet nuget locals all --clear
Restore with detailed logging
dotnet restore --verbosity detailed
Check for locked packages
cat packages.lock.json Lock Files For reproducible builds, use package lock files:
< PropertyGroup
< RestorePackagesWithLockFile
true </ RestorePackagesWithLockFile
</ PropertyGroup
Then commit packages.lock.json files. Anti-Patterns Don't: Edit XML Directly
< PackageReference Include = " Typo.Package " Version = " 1.0.0 " />
Don't: Inline Versions with CPM
< PackageReference Include = " Serilog " Version = " 4.0.0 " />
< PackageReference Include = " Serilog " /> Don't: Mix Version Management
< PackageReference Include = " Serilog " />
< PackageReference Include = " Newtonsoft.Json " Version = " 13.0.3 " />
Don't: Forget Shared Variables
< PackageVersion Include = " Akka " Version = " 1.5.59 " /> < PackageVersion Include = " Akka.Cluster " Version = " 1.5.58 " />
<
PackageVersion
Include
=
"
Akka
"
Version
=
"
$(AkkaVersion)
"
/>
<
PackageVersion
Include
=
"
Akka.Cluster
"
Version
=
"
$(AkkaVersion)
"
/>
Quick Reference
Task
Command
Add package
dotnet add package