PackageReference
|
This section documents MSBuild 18.9, the .NET SDK 10.0.402 (with its This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The C# Reference bibliography lists the reference material consulted while preparing these pages. |
PackageReference is the item that declares a NuGet dependency in an SDK-style project. Its Version is covered on
Package Versions and Ranges; this
page covers everything else — which parts of a package flow where, the per-reference switches, multi-targeting and
the pruning that .NET 10 added — with NuGet 7.9.0 in .NET SDK 10.0.402.
The basics
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Bcl.HashCode" Version="6.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
</ItemGroup>
A Condition on $(TargetFramework) restricts a reference to one framework of a multi-targeted project — Ledgerline
uses exactly this for its netstandard2.0 polyfills. In a repository with Central Package Management the Version
moves to Directory.Packages.props
(Central Package Management).
Controlling assets
Three metadata decide which asset groups of a package (How Package Installation Works) the project uses and which flow to projects or packages that depend on it:
| Metadata | Meaning | Default |
|---|---|---|
|
assets this project consumes |
|
|
assets this project does not consume |
|
|
assets consumed here but not flowed to dependents |
|
Values: compile, runtime, contentFiles, build, buildMultitargeting, buildTransitive, analyzers, native,
none, all.
The effect is clearest on a packed library. Pa references three packages:
<ItemGroup>
<PackageReference Include="Ledgerline.Money" Version="2.0.0" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" PrivateAssets="all" />
<PackageReference Include="Ledgerline.Rates" Version="1.0.0" ExcludeAssets="compile" />
</ItemGroup>
dotnet pack -o out && unzip -p out/Pa.1.0.0.nupkg Pa.nuspec
<dependencies>
<group targetFramework="net10.0">
<dependency id="Ledgerline.Money" version="2.0.0" exclude="Build,Analyzers" />
<dependency id="Ledgerline.Rates" version="1.0.0" exclude="Compile,Build,Analyzers" />
</group>
</dependencies>
-
Default —
Ledgerline.Moneyis a dependency of the package, withBuild,Analyzersexcluded: the defaultPrivateAssetskeeps build logic and analyzers from flowing to consumers. -
PrivateAssets="all"—Humanizer.Coredisappeared from the package’s dependencies. That is right for build-time-only packages (analyzers, Source Link,Microsoft.Build.*for tasks), and wrong here:Pacalls Humanizer at run time, so every consumer would fail withFileNotFoundException. -
ExcludeAssets="compile"— excluded for this project and recorded as excluded for consumers too.
Per-reference switches
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" GeneratePathProperty="true" />
<PackageReference Include="Ledgerline.Legacy" Version="1.0.0" NoWarn="NU1701" />
<PackageReference Include="Ledgerline.Money" Version="2.0.0" Aliases="MoneyV2" />
</ItemGroup>
-
GeneratePathPropertycreates$(Pkg<Id with . replaced by _>)pointing at the package’s folder, for build logic that needs a file from a package:dotnet msbuild -getProperty:PkgHumanizer_Core~/.nuget/packages/humanizer.core/2.14.1 -
NoWarnon the item suppresses a NuGet warning for that package only — the NU1701 of thenet48-only package disappeared from the restore while NU1701 for any other package would still be reported. -
Aliasesputs the package’s assemblies under anextern alias(extern alias MoneyV2;) instead of the global namespace, for two packages that define the same type names. -
IsImplicitlyDefinedis set by SDK authors on references an SDK adds automatically: it tells NuGet tooling the version is controlled by the SDK, so the Visual Studio package manager anddotnet package updatedo not offer upgrades for it.
AssetTargetFallback
When a package has no assets compatible with the project’s framework, AssetTargetFallback lists frameworks to try
instead. For .NET projects the SDK sets it to the .NET Framework versions, which is how Ledgerline.Legacy (only
lib/net48) restored into a net10.0 project — with NU1701 naming every fallback framework
(Dependency Resolution). Adding to it
(<AssetTargetFallback>$(AssetTargetFallback);…</AssetTargetFallback>) is rarely the right fix; a compatible package
version is.
Source: AssetTargetFallback.
Duplicate frameworks
From NuGet 7.6 (SDK 10.0.300) a project can list the same framework twice under different aliases in
TargetFrameworks — for example to build against two versions of a dependency — and NuGet keeps the graphs apart;
invalid alias combinations are reported as NU1018 and NU1019
(Target Frameworks and Runtime Identifiers).
Package pruning
Many packages that once filled gaps — System.Text.Json, System.Memory, System.Collections.Immutable — are part
of the shared framework in modern .NET. Pruning (on by default for net10.0 and later) removes such packages from
the restore graph when the framework already provides them. Ledgerline.Json is a netstandard2.0 package that
depends on System.Text.Json 8.0.5 and System.Memory 4.5.5:
dotnet restore --force -p:RestoreEnablePackagePruning=true
dotnet restore --force -p:RestoreEnablePackagePruning=false
pruning=true -> Ledgerline.Json/1.0.0
pruning=false -> Ledgerline.Json/1.0.0, System.Memory/4.5.5, System.Text.Json/8.0.5
(the packages in the assets file’s net10.0 target). With pruning, the old System.Text.Json 8.0.5 never reaches the
build — and no vulnerability audit warning about it can appear either. A direct reference to a framework-provided
package is not pruned but reported:
~/ledgerline/samples/Deps/Deps.csproj : warning NU1510: PackageReference System.Text.Json will not be pruned. This package is automatically available and does not need to be referenced explicitly. Remove the PackageReference item.
PrunePackageReference items (normally supplied by the SDK) list what is pruned and up to which version. The .NET 10
what’s-new page presents pruning under the NuGet Audit feature, but it is a restore feature: it changes the graph that
is built, not only what is audited.
PackageDownload
PackageDownload downloads a package into the global-packages folder without referencing it — no assets, no
dependencies — for build steps that need its files (a code generator, a native tool). Its version must be exact:
<PackageDownload Include="Ledgerline.Money" Version="[1.5.0]" />
restored with no package in the target graph and the download recorded in the assets file ('version': '[1.5.0,
1.5.0]'). Written as Version="1.5.0", the restore failed without any NuGet message:
~/.dotnet/sdk/10.0.402/NuGet.targets(198,5): error MSB4181: The "RestoreTask" task returned false but did not log an error. [~/ledgerline/samples/Deps/Deps.csproj]
Common mistakes
-
PrivateAssets="all"on a runtime dependency of a library — it vanishes from the package. -
Referencing
System.Text.Jsonand friends innet10.0projects — NU1510; remove the reference. -
Project-wide
NoWarnfor a package-specific warning — use the item’sNoWarn. -
A non-exact
PackageDownloadversion — MSB4181 with no explanation.