Package Sources and Source Mapping
|
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. |
A package source is anywhere NuGet can find packages: nuget.org, a folder, a file share, or an HTTP feed such as
Azure Artifacts, GitHub Packages or a self-hosted BaGetter. With more than one source configured, package source
mapping decides which source may supply each package ID — the defence against a public package impersonating a
private one. This page uses NuGet 7.9.0 (.NET SDK 10.0.402), a folder feed and a BaGetter instance on
localhost:5555. Configuration files themselves are covered on
nuget.config; hosting a feed on
Private Feeds.
Kinds of sources
-
nuget.org —
https://api.nuget.org/v3/index.json, the public registry. -
Local folders and file shares — a path. NuGet reads two layouts: flat (all
.nupkgfiles in one folder) and hierarchical (<id>/<version>/<id>.<version>.nupkgplus the.nuspecand hash), which is faster for large feeds.nuget.exe initandnuget.exe addcreate the hierarchical layout.dotnet nuget pushto a folder produced a flat one — and failed when the folder did not exist yet:Pushing Ledgerline.Money.1.5.0.nupkg to '~/srcs/hfeed'... error: Could not find a part of the path '~/srcs/hfeed/Ledgerline.Money.1.5.0.nupkg'.After
mkdir hfeedthe same command printedYour package was pushed.and the folder heldhfeed/Ledgerline.Money.1.5.0.nupkg. -
HTTP feeds — a V3 service index URL (NuGet Server API).
Source: Local feeds: Hierarchical folders.
HTTPS is required
A source that is plain http:// is an error since NuGet 6.12 (.NET 9 SDK):
~/srcs/P/P.csproj : error NU1302: You are running the 'restore' operation with an 'HTTP' source: http://localhost:5555/v3/index.json. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information.
The opt-out is per source:
<add key="bagetter" value="http://localhost:5555/v3/index.json" allowInsecureConnections="true" />
after which the restore succeeded. It is acceptable for a feed on localhost; anywhere else, plain HTTP lets anyone on
the network replace packages and read credentials.
The rollout, per the documentation: NU1803 warnings from NuGet.exe 6.3, Visual Studio 17.3 and ".NET 6.0.100", and
NU1302 errors from 6.12, 17.12 and .NET 9.0.100. The middle entry is inconsistent: SDK 6.0.100 shipped NuGet 6.0,
not 6.3 (6.3 came with SDK 6.0.400). Likewise, the dotnet nuget add source page says --allow-insecure-connections
is "available since .NET 9 SDK", while the NuGet 6.11 release notes place it in SDK 8.0.400.
Managing sources from the CLI
dotnet nuget add source ~/srcs/hfeed --name folder --configfile nuget.config
dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org --configfile nuget.config
dotnet nuget disable source nuget.org --configfile nuget.config
dotnet nuget list source --configfile nuget.config
dotnet nuget enable source nuget.org --configfile nuget.config
Package source with Name: folder added successfully.
Package source with Name: nuget.org added successfully.
Package source with Name: nuget.org disabled successfully.
Registered Sources:
1. bagetter [Enabled]
http://localhost:5555/v3/index.json
2. folder [Enabled]
~/srcs/hfeed
3. nuget.org [Disabled]
https://api.nuget.org/v3/index.json
Package source with Name: nuget.org enabled successfully.
update source changes a URL or credentials (--username, --password, --store-password-in-clear-text,
--valid-authentication-types); remove source deletes one. Without --configfile the commands edit the user
file. Disabling writes a disabledPackageSources entry rather than removing the source.
Package source mapping
Without mapping, NuGet asks every source for every package and takes the first answer that satisfies the version — so a package named like an internal one, published on nuget.org with a higher version, can win ("dependency
confusion"). With a packageSourceMapping section, each package ID may only come from the sources whose patterns match
it:
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="bagetter">
<package pattern="Ledgerline.*" />
<package pattern="Ledgerline" />
</packageSource>
<packageSource key="folder">
<package pattern="Ledgerline.Money" />
</packageSource>
</packageSourceMapping>
Installed Ledgerline 1.0.0 from http://localhost:5555/v3/index.json to ~/srcs/gp/ledgerline/1.0.0 with content hash ImUylbiSkzpcLFJdtr0M…
Installed Ledgerline.Money 1.5.0 from ~/srcs/hfeed to ~/srcs/gp/ledgerline.money/1.5.0 with content hash ikqFv5yDeM68b02nB3Ou…
Installed Humanizer.Core 2.14.1 from https://api.nuget.org/v3/index.json to ~/srcs/gp/humanizer.core/2.14.1 with content hash lQKvtaTDOXnoVJ20ibTu…
(exact ID: most specific)"| F["folder"] Id -->|"Ledgerline, Ledgerline.*
(prefix)"| B["bagetter"] Id -->|"anything else
(* default)"| N["nuget.org"]
The rules:
-
Most specific wins — an exact ID beats a prefix (
Ledgerline.*), a longer prefix beats a shorter one, and*is the lowest; soLedgerline.Moneycame from the folder althoughLedgerline.*also matched the BaGetter source. -
*makes a default source; without one, a package that matches no pattern fails to restore. -
A pattern is a package ID or a prefix ending in
*. -
An unmapped source is not used for restore, which is how Ledgerline's BaGetter source stays a push target only; NU1102 then reports "Versions from … were not considered" (Package Versions and Ranges).
-
The global-packages folder is checked first — a package already there is used without consulting the mapping, so security-sensitive repositories use their own
globalPackagesFolder.
Onboarding an existing repository: map everything to its current source by hand, or generate the section with the
NuGet.PackageSourceMapper tool; then restore with an empty global-packages folder to prove the mapping is complete.
Source mapping has limits: it filters downloads during restore, install and update, but not metadata queries — dotnet package add, dotnet package list --outdated/--deprecated/--vulnerable and the Visual Studio browse and update
lookups still send package IDs to every configured source, including public ones. Internal package names can therefore
leak to nuget.org in those queries.
Common mistakes
-
Several sources and no mapping — dependency confusion; CPM repositories also get NU1507.
-
allowInsecureConnectionson a remote feed — move the feed to HTTPS instead. -
Expecting mapping to apply to a warm cache — the global-packages folder short-circuits it.
-
--add-sourcein a mapped repository — refused by tool commands; map the source instead (.NET Tools).