DotNetPublish targeting multiple framework

Summary

This incident centers on a multi‑target .NET project where a custom build script uses DotNetPublish to generate framework‑specific outputs and then produce a NuGet package. After adding net10.0 to the project’s TargetFrameworks, the build no longer produced a NuGet package. The root cause was a misunderstanding of how NuGet packing works in multi‑target projects versus how DotNetPublish behaves.

Root Cause

The failure occurred because:

  • DotNetPublish does not create NuGet packages — it only publishes compiled outputs.
  • The script attempted to publish each framework separately and expected NuGet packaging to happen afterward.
  • Multi‑target NuGet packages must be created using dotnet pack, not by manually merging publish folders.
  • The MSBuild property OutputPackagePath was set, but no pack step was executed, so no .nupkg was produced.
  • Publishing into separate folders (bin/Debug/net9.0, bin/Debug/net10.0) is correct — combining them into one folder is not how NuGet multi‑targeting works.

Why This Happens in Real Systems

This class of issue is common because:

  • Engineers assume publishing and packing are related operations.
  • Build scripts often evolve over time and accumulate incorrect assumptions.
  • Multi‑targeting introduces implicit MSBuild behavior that is easy to overlook.
  • NuGet packaging is metadata‑driven, not folder‑driven.

Real-World Impact

This type of failure typically results in:

  • Missing NuGet packages, blocking deployments.
  • Incorrect package contents, if engineers try to manually merge outputs.
  • Broken downstream builds, because consumers cannot restore the expected frameworks.
  • Wasted CI time, as builds succeed but artifacts are missing.

Example or Code (if necessary and relevant)

A correct multi‑target pack step looks like this:

DotNetPack("./src/abc/abc.csproj", new DotNetPackSettings {
    Configuration = configuration,
    MSBuildSettings = msBuildSettings,
    OutputDirectory = nuGetOutputDirectory
});

And the project file should contain:

net9.0;net10.0

No manual folder merging is required.

How Senior Engineers Fix It

Experienced engineers resolve this by:

  • Separating publish and pack steps — they are different operations.
  • Using dotnet pack (or DotNetPack in Cake) to generate multi‑target NuGet packages.
  • Ensuring the .csproj contains all required metadata:
    • <TargetFrameworks>
    • <PackageId>
    • <Version>
    • <Authors>
  • Avoiding manual manipulation of output folders.
  • Validating the final .nupkg using nuget inspect or dotnet nuget verify.

Why Juniors Miss It

Less‑experienced developers often overlook this because:

  • DotNetPublish sounds like it should produce a package.
  • Multi‑targeting behavior is implicit, not obvious.
  • NuGet packaging is metadata‑driven, not based on folder structure.
  • Build scripts can hide the distinction between publishing and packing.
  • They may assume that “multiple publish outputs” must be merged manually.

This is a classic example of how understanding MSBuild’s mental model is essential for reliable automation.

Leave a Comment