nuget.config

This section documents MSBuild 18.9, the .NET SDK 10.0.402 (with its dotnet CLI) and NuGet 7.9, as published in the MSBuild, .NET and NuGet documentation on learn.microsoft.com, which is the reference these pages are written and verified against. Material about .NET 11 / NuGet 8.0 is still in preview and is always flagged as such — never presented as baseline.

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.

NuGet takes its sources, credentials, folders and policies from nuget.config files. Several files usually apply at once — one in the repository, one per user, sometimes one per machine — and their merge order explains most "it restores on my machine" problems. This page covers the files and every section with NuGet 7.9.0 (.NET SDK 10.0.402), using Ledgerline's configuration.

Which files apply

Level Location

Folder ("solution")

nuget.config (any casing) in the current folder and every parent folder up to the drive root.

User

Windows %appdata%\NuGet\NuGet.Config; macOS/Linux ~/.nuget/NuGet/NuGet.Config for the .NET CLI (Mono tools use ~/.config/NuGet/NuGet.Config). Additional, read-only files: …/NuGet/config/*.config.

Computer

Windows %ProgramFiles(x86)%\NuGet\Config; Linux /etc/opt/NuGet/Config; macOS /Library/Application Support (or $NUGET_COMMON_APPLICATION_DATA/NuGet/Config).

dotnet nuget config paths lists the files that apply in a folder, closest first:

cd ~/ledgerline && dotnet nuget config paths
~/ledgerline/nuget.config
~/.nuget/NuGet/NuGet.Config

The user file was created by the first dotnet NuGet operation on this profile, with nuget.org as its only source. The documentation’s two macOS/Linux user paths are a real inconsistency between tools: the .NET CLI used ~/.nuget/NuGet, as shown.

flowchart TB A["nuget.config in the current folder"] --> B["nuget.config in each parent folder, up to the root"] B --> C["User: ~/.nuget/NuGet/NuGet.Config
(and NuGet/config/*.config)"] C --> D["Computer: /etc/opt/NuGet/Config"] A -. "closest file wins for single values;
lists are merged unless a file says clear" .- D

How settings merge

NuGet reads the files from the computer level up to the closest one. For a single value (globalPackagesFolder), the closest file wins. For lists (packageSources), entries accumulate across files — unless a file contains <clear />, which drops everything inherited from farther files.

A source added at user level:

dotnet nuget add source ~/ledgerline/artifacts/feed --name user-feed
cd ~/scratch && dotnet nuget list source
cd ~/ledgerline && dotnet nuget list source
Package source with Name: user-feed added successfully.
Registered Sources:
  1.  nuget.org [Enabled]
      https://api.nuget.org/v3/index.json
  2.  user-feed [Enabled]
      ~/ledgerline/artifacts/feed
Registered Sources:
  1.  nuget.org [Enabled]
      https://api.nuget.org/v3/index.json
  2.  ledgerline-local [Enabled]
      ~/ledgerline/artifacts/feed
  3.  ledgerline-bagetter [Enabled]
      http://localhost:5555/v3/index.json

Outside the repository the user source applied; inside Ledgerline it did not, because the repository file starts its packageSources with <clear />. A repository that wants identical restores everywhere should <clear /> and list every source it needs — otherwise each developer’s and agent’s user and computer files add sources silently.

NuGetDefaults.Config (in the NuGet program-data folder) is the place for administrators to add default sources and disable others for every user of a machine; it cannot remove sources that users add.

Ledgerline’s nuget.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="ledgerline-local" value="./artifacts/feed" />
    <add key="ledgerline-bagetter" value="http://localhost:5555/v3/index.json" allowInsecureConnections="True" />
  </packageSources>
  <packageSourceMapping>
    <packageSource key="nuget.org">
      <package pattern="*" />
    </packageSource>
    <packageSource key="ledgerline-local">
      <package pattern="Ledgerline" />
      <package pattern="Ledgerline.*" />
    </packageSource>
  </packageSourceMapping>
</configuration>

Relative paths (./artifacts/feed) are relative to the file. The local BaGetter source is plain HTTP and needs allowInsecureConnections, and it is not in the mapping, so no package is ever restored from it — it is a push target only (Package Sources and Source Mapping). dotnet nuget config get all prints the merged result for the current folder:

packageSources:
	clear
	add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3"
	add key="ledgerline-local" value="./artifacts/feed"
	add key="ledgerline-bagetter" value="http://localhost:5555/v3/index.json" allowInsecureConnections="True"

packageSourceMapping:
	packageSource key="nuget.org"
	packageSource key="ledgerline-local"

The sections

Section Contents

config

Single values: globalPackagesFolder, repositoryPath (packages.config), defaultPushSource, http_proxy, signatureValidationMode, maxHttpRequestsPerSource, dependencyVersion, …

packageRestore

enabled, automatic — restore on build in Visual Studio.

packageSources

The sources, with protocolVersion, allowInsecureConnections and (.NET 11) minPublishAgeHours.

auditSources

Sources used only for vulnerability data (Auditing Packages for Vulnerabilities).

packageSourceCredentials

Per-source Username, Password/ClearTextPassword, ValidAuthenticationTypes (Authenticated Feeds and Credential Providers).

apikeys

Encrypted push keys stored by nuget.exe setapikey.

disabledPackageSources

Sources listed but disabled.

activePackageSource

Visual Studio’s selected source.

trustedSigners

Trusted authors and repositories (Signed Packages and Trust Policies).

fallbackPackageFolders

Read-only folders searched before downloading.

packageSourceMapping

Which source may supply which package IDs.

packageManagement

format (0 PackageReference, 1 packages.config) and disabled — Visual Studio defaults.

bindingRedirects, solution

Visual Studio / packages.config settings.

Environment variables

Values can reference environment variables as %NAME% on every platform:

<packageSources>
  <add key="team" value="%LEDGER_FEED%" />
</packageSources>
LEDGER_FEED=/srv/feeds/ledger dotnet nuget list source
Registered Sources:
  1.  team [Enabled]
      /srv/feeds/ledger
  2.  nuget.org [Enabled]
      https://api.nuget.org/v3/index.json

This is how CI supplies tokens without committing them: <add key="ClearTextPassword" value="%FEED_TOKEN%" /> in packageSourceCredentials. The folder file (team) is listed before the user file’s sources.

Changing settings from the CLI

dotnet nuget config set defaultPushSource https://example.invalid/v3/index.json --configfile ./nuget.config
dotnet nuget config unset defaultPushSource --configfile ./nuget.config

set added a <config> section to the file:

<config>
  <add key="defaultPushSource" value="https://example.invalid/v3/index.json" />
</config>

Without --configfile, set and unset change the user file. get <key> prints one effective value (--show-path adds the file it came from); for a key that no file sets, it printed error: Key 'globalPackagesFolder' not found. — even though the folder has a default — so use dotnet nuget locals global-packages --list for folder locations.

Common mistakes

  • No <clear /> in the repository file — user and machine sources leak into restores.

  • A nuget.config in a project folder — it only applies to commands run from that folder or below.

  • Credentials committed in packageSourceCredentials — use %VARIABLES% or a credential provider.

  • Expecting dotnet nuget config get to show defaults — it shows configured values only.