Publishing and Distributing Libraries
|
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. |
The NuGet group covers consuming packages; this group
covers producing them: designing a library for reuse, describing it, packing, validating, signing, versioning and
publishing it, and looking after it once it is public. Every example was run with .NET SDK 10.0.402 (MSBuild 18.9,
NuGet 7.9.0) on Linux, against the Ledgerline scenario of this section. Packages were pushed only to a local
folder feed and to a BaGetter 1.6.5 container on localhost:5555; pushes to nuget.org, GitHub Packages and Azure
Artifacts, Trusted Publishing and signing with a real certificate are shown as "not run here" examples, checked against
the documentation, with placeholder keys. Ledgerline is never pushed to a public feed.
The life of a release
targets, dependencies"] --> M["Describe
metadata, README,
icon, licence"] M --> P["Build and pack
dotnet pack"] P --> V["Validate
package validation,
API compatibility"] V --> S["Sign
(optional)"] S --> L[("Local folder feed")] S --> T[("Test feed
BaGetter, int.nugettest.org")] T --> N[("nuget.org
Trusted Publishing")] N --> A["After release
unlist, deprecate,
vulnerabilities"]
A release starts long before dotnet pack: the target frameworks and dependency ranges chosen at design time decide
who can consume the package, and the metadata decides whether anyone finds and trusts it. Packing turns a project into a
.nupkg; validation compares it with the previous release; signing is optional on nuget.org, which adds its own
repository signature. Pushing to a test feed first catches packaging mistakes before they become permanent, because a
version on nuget.org can be unlisted but never replaced.
The tool chain
| Step | dotnet CLI | Other tools |
|---|---|---|
Pack |
|
|
Sign |
|
|
Push |
|
|
Authenticate to nuget.org |
|
scoped API keys |
Unlist |
|
the nuget.org package page; |
A minimal local release of Ledgerline is two commands:
dotnet pack src/Ledgerline -o artifacts/rel -p:Version=1.0.1 -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
dotnet nuget push artifacts/rel/Ledgerline.1.0.1.nupkg -s ledgerline-bagetter -k "$BAGETTER_API_KEY"
Pushing Ledgerline.1.0.1.nupkg to 'http://localhost:5555/api/v2/package'...
PUT http://localhost:5555/api/v2/package/
Created http://localhost:5555/api/v2/package/ 86ms
Your package was pushed.
Pushing Ledgerline.1.0.1.snupkg to 'http://localhost:5555/api/v2/symbol'...
PUT http://localhost:5555/api/v2/symbol/
Created http://localhost:5555/api/v2/symbol/ 60ms
Your package was pushed.
dotnet nuget push found the .snupkg next to the .nupkg and pushed it to the feed’s symbol endpoint without being
asked.
Where packages can go
-
nuget.org — the public registry, the default source of every client (Publishing to nuget.org).
-
GitHub Packages and Azure Artifacts — hosted private (or public) feeds tied to a repository or an Azure DevOps organization.
-
Self-hosted servers — BaGetter, NuGet.Server, or any server implementing the NuGet V3 API.
-
Folders and file shares — the simplest feed, with no server at all.
The last three are covered on Private Feeds.
Source: Hosting your own NuGet feeds.
Dated changes
| Date / release | Change |
|---|---|
NuGet 4.3 (2017) |
SemVer 2.0.0 package versions |
NuGet 4.9 (2018) |
|
NuGet 5.0 (2019) |
|
NuGet 5.3 / VS 16.3 (2019) |
embedded icon ( |
NuGet 5.10 preview 2 (2021) |
embedded README ( |
.NET 6 SDK (2021) |
package validation; |
NuGet 6.4 (2022) |
Central Package Management GA |
.NET 8 SDK (2023) |
Source Link built into the SDK; the commit hash in |
NuGet 6.12 / .NET 9 (2024) |
SHA-1 certificate fingerprints deprecated in the sign commands |
.NET 10 SDK (2025-11-11) |
RID-specific, self-contained and Native AOT .NET tools, the |
2025-09-22 |
Trusted Publishing on nuget.org announced (GitHub Actions; GitLab later); the |
NuGet 7.3 (10.0.200) |
deterministic file order inside packages |
NuGet 7.6 (10.0.300) |
pack aware of TFM aliases (NU5051) |
NuGet 7.9 (10.0.400) |
deterministic pack revisited: |
2026-08-17 |
new nuget.org API keys expire after at most 30 days; the 365-day option is gone. Every key created before that date expires on 2026-11-01. |
.NET 11 (preview) |
NETSDK1235 ( |
The API key change is announced on the .NET blog (2026-08-03); no Microsoft Learn page states it yet, and Scoped API keys still shows a 365-day key (nuget.org Accounts, Organizations and API Keys).
Reading order
Overview and design — Designing a Library for NuGet, Package Metadata, README, Icon and License.
Building packages — Creating Packages with dotnet pack, Package Layout and Multi-Targeting, MSBuild Props, Targets, Tasks and Analyzers in Packages, Versioning and Prerelease Packages, Symbols, Source Link and Deterministic Packages, Package Validation and API Compatibility.
Signing, tools and templates — Signing Packages, Tool and Template Packages.
Publishing — nuget.org Accounts, Organizations and API Keys, Publishing to nuget.org, Trusted Publishing, Private Feeds, CI Release Workflows, Managing Published Packages.
Reference — Pack and Push Errors, Release Checklist.
Common mistakes
-
Pushing to nuget.org first — a version is permanent; try a local or test feed first.
-
Treating the API key as long-lived — since 2026-08-17 it lasts 30 days at most; prefer Trusted Publishing.
-
Skipping package validation — a removed public member is a breaking change that consumers find at run time.