Publishing to nuget.org
|
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. |
Publishing is one command, but a permanent one: a version pushed to nuget.org can be unlisted and deprecated, never
replaced or (in practice) deleted. This page covers the push itself, what nuget.org checks afterwards and how to rehearse
the whole round trip first. The round trip was run against the BaGetter 1.6.5 feed on localhost:5555 with .NET
SDK 10.0.402 (NuGet 7.9.0); every nuget.org command is "not run here", with placeholder keys. Getting a key is on
nuget.org Accounts, Organizations and API Keys;
pushing from CI without a stored key on
Trusted Publishing.
Pushing
Three ways to get a package onto nuget.org:
-
The web portal — Upload on nuget.org, select the
.nupkg, review the metadata (with a README preview) and Submit. Good for a first, manual push. -
dotnet nuget push— the CLI form, for scripts and CI:dotnet nuget push artifacts/Ledgerline.1.0.1.nupkg --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json -
nuget push(nuget.exe 4.1.0+), with a key saved bynuget setApiKey.
The dotnet nuget push options:
| Option | Meaning |
|---|---|
|
Server URL or a source name from |
|
The key; |
|
Treat |
|
Where |
|
Don’t push symbols even if present. |
|
Seconds per push; 300 by default (0 also means the default). |
|
Use only this |
|
Allow credential prompts; don’t append |
Wildcards push many packages at once: dotnet nuget push "artifacts/*.nupkg" --skip-duplicate.
The round trip, rehearsed on BaGetter
The Ledgerline repository’s nuget.config lists the BaGetter feed as ledgerline-bagetter (HTTP, so with
allowInsecureConnections="true", acceptable only on localhost). Pack and push:
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.
A consumer, Ledgerline.Report, referencing Ledgerline 1.0.1 with source mapping to the same feed — the first
restore failed:
error NU1102: Unable to find package Ledgerline with version (>= 1.0.1)
error NU1102: - Found 1 version(s) in ledgerline-bagetter [ Nearest version: 1.0.0 ]
error NU1102: - Versions from nuget.org were not considered
The feed already listed 1.0.1 (curl .../v3/package/ledgerline/index.json returned {"versions":["1.0.0","1.0.1"]});
the machine’s HTTP cache still held the version list from an earlier restore, valid for 30 minutes. A restore with
--no-http-cache found it and the program printed the assembly version, 1.0.1.0. In CI that tests a just-published
package, use --no-http-cache.
Pushing the same version again, then with --skip-duplicate:
Pushing Ledgerline.1.0.1.nupkg to 'http://localhost:5555/api/v2/package'...
PUT http://localhost:5555/api/v2/package/
Conflict http://localhost:5555/api/v2/package/ 63ms
To skip already published packages, use the option --skip-duplicate
error: Response status code does not indicate success: 409 (Conflict).
Pushing Ledgerline.1.0.1.nupkg to 'http://localhost:5555/api/v2/package'...
PUT http://localhost:5555/api/v2/package/
Conflict http://localhost:5555/api/v2/package/ 62ms
Package '.../artifacts/rel/Ledgerline.1.0.1.nupkg' already exists at feed 'http://localhost:5555/api/v2/package'.
The first exited with 1, the second with 0. nuget.org also answers 409 for an existing version; the exact message
text it returns is not documented, so the BaGetter output stands in for it here.
What happens after the push
The push returns as soon as the gallery accepts the upload; nuget.org then validates the package asynchronously (signature requirements, malware scanning, symbol checks) and adds its repository signature before the package shows up in search and restore. That usually takes under 15 minutes; after an hour, check status.nuget.org and then contact support from the package page.
Limits:
-
Package ID — letters, digits, dots and dashes, no consecutive dots or dashes, at most 100 characters. The publishing page lets an ID start with an underscore; the NU5052 reference says letter or digit only (Package Metadata).
-
Size — about 250 MB; keep packages under 1 MB if possible and split assets into dependency packages. Larger uploads fail with
error: Response status code does not indicate success: 413 (The package file exceeds the size limit. Please try again.).(quoted from the documentation). -
Metadata is immutable. Description, README, licence and dependencies cannot be edited after upload — signed content includes the
.nuspec. A fix is a new version.
Testing on the integration gallery (not run here)
nuget.org runs a separate test site, int.nugettest.org, with its own accounts and keys; its V3 endpoint is
https://apiint.nugettest.org/v3/index.json. Pushing there first shows the real validation, README rendering and
search listing without making anything public on nuget.org:
dotnet nuget push artifacts/Ledgerline.1.0.1.nupkg -k "$NUGETTEST_API_KEY" -s https://apiint.nugettest.org/v3/index.json
Source: FAQ: int.nugettest.org.
ID prefix reservation
An owner can reserve an ID prefix such as Ledgerline.*. nuget.org then refuses new packages with that prefix from
other accounts, and shows a verified checkmark on the owner’s packages there and in Visual Studio. Advanced options:
delegating sub-prefixes (Ledgerline.Build.*) to other owners, and public prefixes that keep the checkmark but stay
open to submissions (for community projects). Packages that other owners already had under the prefix stay, without
the checkmark, and can still get new versions. The Visual Studio indicator needs VS 2017 15.4+ and a single selected
package source.
Apply by e-mail to account@nuget.org with the owner and the prefixes. The criteria: the prefix clearly identifies the
owner; it is not a common or generic word and has at least four characters; and not reserving it would cause confusion.
Packages under a reserved prefix are expected to follow the authoring best practices — consistent authors, a license
element (not licenseUrl) and an embedded icon. Disputes go to support@nuget.org.
Account security
The library guidance: ✔️ DO enable two-factor authentication and ✔️ DO enable e-mail notification when a package is published, so an unexpected version is noticed. The same page (2018) still recommends MyGet for CI prereleases and says nothing about Trusted Publishing, scoped keys or signing; GitHub Packages, Azure Artifacts or a self-hosted feed (Private Feeds) take that role today.
Source: Library guidance: nuget.org security.
Common mistakes
-
Publishing straight from a laptop — use a CI job, ideally with Trusted Publishing.
-
No
--skip-duplicatein a re-runnable job — a retried job fails on the packages that already went out. -
Testing a just-pushed version through the HTTP cache — NU1102 for half an hour; use
--no-http-cache. -
A 300 MB package —
413; move native or content assets into dependency packages. -
Fixing a typo by re-uploading — impossible; publish a new version.