Package Metadata, README, Icon and License
|
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. |
Metadata is what a consumer sees before deciding to install a package: the ID and description in search results, the
README, icon and licence on the package page, the repository link that lets them check the source. NuGet’s
package authoring best practices
give a rule for each property; this page lists them, packs Ledgerline with all of them, and reproduces every pack
error for the README, icon and licence with .NET SDK 10.0.402 (NuGet 7.9.0).
The properties
| MSBuild property | .nuspec element |
Rule |
|---|---|---|
|
|
✔️ DO choose a unique ID, clearly different from existing ones; ✔️ CONSIDER a prefix that meets the prefix-reservation criteria. Defaults to the assembly name. |
|
|
✔️ CONSIDER SemVer; ✔️ DO publish a prerelease if the package is not stable (Versioning). |
|
|
✔️ DO use the "pretty name" of the person or organization. Defaults to the assembly name. |
|
|
✔️ DO include a short description (up to 4000 characters). Defaults to |
|
|
✔️ DO add |
|
|
✔️ DO link the project, repository or website. |
|
|
Filled in by Source Link; set |
|
|
✔️ DO include several tags (semicolon-separated in MSBuild, space-separated in the |
|
|
✔️ DO include release notes with each update. |
|
|
|
|
|
Human-friendly title; defaults to the ID. |
|
|
See the sections below. |
Owners and Summary from the .nuspec have no MSBuild equivalent. An ID must be at most 100 characters, use only
ASCII letters, digits, dots and dashes, and must not contain consecutive dots or dashes. The two documents disagree on
the first character: nuget.org’s publishing page allows a letter, digit or underscore, the NU5052 reference a letter
or digit. With SDK 10.0.402, invalid IDs failed with errors that carry no code — not the NU5052 warning the
reference describes:
error : The package ID 'Ledger line!' contains invalid characters. Examples of valid package IDs include 'MyPackage' and 'MyPackage.Sample'.
error : Id must not exceed 100 characters.
A project with no metadata at all packs without a warning, as <authors>Defaults</authors> and
<description>Package Description</description> — nuget.org accepts that, so nothing but review stops it.
The Ledgerline metadata
Shared values live in Directory.Build.props; the README and icon at the repository root are packed by
Directory.Build.targets for every packable project:
<!-- Directory.Build.props -->
<PropertyGroup>
<Authors>Ledgerline contributors</Authors>
<Copyright>Copyright (c) Ledgerline contributors</Copyright>
<RepositoryUrl>https://example.com/ledgerline/ledgerline</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://example.com/ledgerline</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
<!-- Directory.Build.targets -->
<ItemGroup Condition="'$(IsPackable)' == 'true'">
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" Visible="false" />
<None Include="$(MSBuildThisFileDirectory)icon.png" Pack="true" PackagePath="\" Visible="false" />
</ItemGroup>
The project adds the ID, version, description and tags. The .nuspec inside the packed Ledgerline.1.0.0.nupkg:
<metadata>
<id>Ledgerline</id>
<version>1.0.0</version>
<authors>Ledgerline contributors</authors>
<license type="expression">MIT</license>
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
<icon>icon.png</icon>
<readme>README.md</readme>
<projectUrl>https://example.com/ledgerline</projectUrl>
<description>Double-entry bookkeeping ledgers: read journal CSV files, check that every entry balances and export a trial balance as JSON.</description>
<copyright>Copyright (c) Ledgerline contributors</copyright>
<tags>ledger accounting double-entry trial-balance csv</tags>
<repository type="git" url="https://example.com/ledgerline/ledgerline" commit="e33226ff8326b40770b01db9cc78bfd2d7044fc8" />
...
</metadata>
Pack added two things nobody wrote: a licenseUrl pointing to licenses.nuget.org, for clients older than the license
element, and the git commit of the build, from Source Link.
The README
PackageReadmeFile names a Markdown file in the package (added in NuGet 5.10 preview 2, per the .nuspec
reference; the release notes don’t mention it). The file must be packed explicitly, as above, and nuget.org renders it
on the package page. The rules:
-
✔️ DO add a README that says what the package does and how to get started — a short code sample, links to docs, the licence and how to get help.
-
nuget.org supports CommonMark through Markdig: headers, images, emphasis, lists, links, block quotes, code spans with syntax highlighting, task lists, tables, emoji and auto-links — no raw HTML.
-
Images and badges render only from an allow-list of domains — among them
img.shields.io,badgen.net,codecov.io,coveralls.io,dev.azure.com,raw.githubusercontent.com,user-images.githubusercontent.comand GitHub Actions workflow badges. Relative image paths and other domains are not rendered, with a warning visible only to the owners. -
To preview it, start an upload on nuget.org’s Upload Package page and look at the "Readme File" section before submitting; fixing it later needs a new version.
The pack errors, each reproduced with a one-file project:
error NU5039: The readme file 'README.md' does not exist in the package.
error NU5038: The readme file 'readme.txt' has an invalid extension. It must end in .md.
error NU5040: The readme file 'README.md' is empty.
NU5039 is what most people meet first: setting PackageReadmeFile without the None ... Pack="true" item.
The icon
PackageIcon names a PNG or JPEG inside the package, at most 1 MB; 128×128 is recommended. It replaced
PackageIconUrl in NuGet 5.3 / Visual Studio 16.3. The icon.png of Ledgerline is a 128×128 RGBA PNG of 680 bytes.
error NU5046: The icon file 'icon.png' does not exist in the package.
error NU5045: The 'icon' element 'icon.bmp' has an invalid file extension. Valid options are .png, .jpg or .jpeg.
error NU5047: The icon file size must not exceed 1 megabyte.
warning NU5048: The 'PackageIconUrl'/'iconUrl' element is deprecated. Consider using the 'PackageIcon'/'icon' element instead. Learn more at https://aka.ms/deprecateIconUrl
The documentation contradicts itself on icons. The best-practices page says ✔️ DO use a 128×128 image with a
transparent background and ❌ DO NOT use the deprecated IconUrl; the library guidance’s
NuGet page (2026) still says ✔️ DO use an
HTTPS href to the icon at 64×64; and the pack-target reference suggests setting PackageIconUrl in addition to
PackageIcon "for the best downlevel experience", which triggers no warning when both are present. Embed a 128×128 PNG;
add PackageIconUrl only if very old clients matter.
The licence
A package declares its licence in one of two ways (since NuGet 4.9):
-
PackageLicenseExpression— an SPDX expression such asMIT,Apache-2.0orMIT OR Apache-2.0. Pack addslicenseUrlpointing tohttps://licenses.nuget.org/<expression>, which shows the SPDX text. nuget.org accepts only identifiers approved by the OSI or the FSF. -
PackageLicenseFile— a.txtor.mdfile packed into the package, for custom or non-standard licences.
The best practices: ✔️ DO include a licence expression or file; ❌ DO NOT use the deprecated PackageLicenseUrl;
✔️ CONSIDER an expression for open-source packages (consumers and tools read it directly); ✔️ DO include a licence file
for closed-source ones. The errors:
error NU5030: The license file 'LICENSE.txt' does not exist in the package.
error NU5032: The license expression 'GPL-2.0' cannot be parsed succesfully. The identifier 'GPL-2.0' is deprecated.
error NU5033: Invalid metadata. Cannot specify both a PackageLicenseExpression and a PackageLicenseFile.
error NU5035: The PackageLicenseUrl is being deprecated and cannot be used in conjunction with the PackageLicenseFile or PackageLicenseExpression.
warning NU5124: The license identifier 'Foo-1.0' is not recognized by the current toolset.
warning NU5125: The 'licenseUrl' element will be deprecated. Consider using the 'license' element instead.
(NU5032 is quoted as printed, typo included; GPL-2.0 is deprecated in SPDX in favour of GPL-2.0-only and
GPL-2.0-or-later.) NU5124 is a warning because the client’s SPDX list can be older than the licence — but nuget.org
validates the expression on upload against its own list. A project with no licence at all packs without any
warning.
Common mistakes
-
Setting
PackageReadmeFileorPackageIconwithout packing the file — NU5039 and NU5046. -
Badges from an unlisted domain — they silently disappear on nuget.org.
-
Leaving
AuthorsandDescriptionat their defaults — the package saysPackage Descriptionforever (metadata cannot be edited after upload). -
A deprecated SPDX identifier — use
GPL-2.0-only, notGPL-2.0. -
Putting both a licence expression and a licence file — NU5033.