Build Automation Tools (MSBuild, dotnet CLI & NuGet)

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.

"Build automation" in .NET means that a single command — dotnet build, dotnet test, dotnet pack or dotnet publish — turns a source tree into tested binaries, NuGet packages or a deployable application, the same way on every developer machine and every CI agent. Unlike the JVM world, where Maven and Gradle compete, or Python, where standards connect interchangeable tools, .NET ships one tool chain from one vendor, split into three parts that are always used together:

  • MSBuild, the engine. It reads the XML project files (.csproj, .props, .targets), evaluates their properties and items, and runs targets made of tasks. Every .NET build, whether started from a terminal, Visual Studio, Rider or VS Code, is an MSBuild build.

  • The .NET SDK and its dotnet CLI, the driver. The SDK carries MSBuild, the Roslyn compilers, NuGet, the project SDKs (Microsoft.NET.Sdk and friends) and the templates; the dotnet command is a thin front end that picks an SDK, translates its options into MSBuild switches and invokes the right targets.

  • NuGet, the package manager. It is built into both MSBuild (the Restore and Pack targets) and the CLI (dotnet package, dotnet nuget). It resolves PackageReference items against package sources, downloads .nupkg files into the global-packages folder and writes the assets file that the compiler reads.

The introduction to these tools is already on two pages of the C# Reference: Build and Tooling (the dotnet CLI, a first look at packing, tools, MSBuild, symbols and CI) and Namespaces, Assemblies and Projects (SDK-style projects, multi-targeting, global.json, NuGet consuming and authoring, deployment models). This section goes much deeper and does not repeat them. It is the .NET counterpart of the JVM build tools section (issue #300) and the Python build tools section (issue #305); the sections share no pages.

The pages were written against MSBuild 18.9, the .NET SDK 10.0.402 and NuGet 7.9.0. Every example was run with SDK 10.0.402 installed by dotnet-install.sh --version 10.0.402 into a scratch directory on Ubuntu 24.04 (x64), on 2026-10-23; long absolute paths in the output are shortened to ~/ledgerline and <sdk> (the SDK folder).

One engine, one driver, one package manager

flowchart LR CMD["dotnet build"] --> RES["SDK resolution: dotnet host + global.json"] RES --> REST["NuGet restore: PackageReference to project.assets.json"] REST --> EVAL["MSBuild evaluation: properties, items, imports"] EVAL --> EXEC["MSBuild execution: targets and tasks"] EXEC --> CSC["Roslyn compiler: CoreCompile"] CSC --> OUT["Outputs: bin/ and obj/"] OUT --> PACK["dotnet pack: .nupkg and .snupkg"] OUT --> PUB["dotnet publish: deployable app"] PACK --> FEED[("Package source: nuget.org, private feed, folder")] FEED --> REST

The diagram is the life of every build; the next page, How a .NET Build Works, follows it step by step. The table below shows which part of the tool chain owns each step.

Step MSBuild .NET SDK / dotnet CLI NuGet

Choose the tools

 — 

The dotnet host reads global.json and selects an SDK (and with it an MSBuild and a NuGet)

 — 

Get dependencies

Runs the Restore target

dotnet restore, implicit restore in build/test/pack/publish

Resolves versions, downloads packages, writes project.assets.json

Describe the build

Evaluates the project, .props, .targets and the project SDK

Provides the project SDKs (Microsoft.NET.Sdk, .Web, …) and their defaults

Generates nuget.g.props/nuget.g.targets that import package build logic

Run the build

Executes targets and tasks (CoreCompile, Copy, …), incrementally and in parallel

dotnet build, test, run, clean, format, watch

 — 

Produce packages and apps

Runs Pack and Publish targets

dotnet pack, dotnet publish, container images

Writes the .nupkg/.snupkg; dotnet nuget push uploads them

The dotnet CLI is a driver in the strict sense: the documentation states that "running dotnet build is equivalent to running dotnet msbuild -restore; however, the default verbosity of the output is different", and every building command accepts MSBuild switches such as -p: and -v:. NuGet appears twice: as MSBuild targets (Restore, Pack) inside every build, and as the dotnet nuget / dotnet package commands for everything outside a build (sources, push, signing, search).

Checking which tools you have

The three versions come from one SDK installation. dotnet --version prints the SDK that the current directory selects (through global.json, if any); dotnet msbuild -version prints the MSBuild that SDK carries; and dotnet nuget --version prints the NuGet client in it.

dotnet --version
dotnet msbuild -version
dotnet nuget --version
dotnet --list-sdks
10.0.402
18.9.15.50611
7.9.0-rc.611+a8dd0577c5c13f43a2f57fe33b4ff11b90f6371e.a8dd0577c5c13f43a2f57fe33b4ff11b90f6371e
10.0.402 [<dotnet>/sdk]

The NuGet line deserves a remark: the NuGet assemblies inside SDK 10.0.402 carry the informational version 7.9.0-rc.611+<commit>, although the SDK’s release notes and nuget.exe call the release 7.9.0. The NuGet release notes list SDK 10.0.400 as the SDK that ships NuGet 7.9; the suffix is a build label, not a sign of a preview client.

Release baseline

These are the releases the section documents, re-verified on 2026-10-23 against the .NET release metadata, the NuGet APIs and the release notes. Newer releases are mentioned only in clearly labelled passages.

Tool Baseline Also covered Notes

.NET SDK

10.0.402 (2026-10-13; runtime 10.0.13; .NET 10 is LTS, supported until 2028-11-14)

11.0.100-rc.2.26504.105 (2026-10-13, "go-live" release candidate) in preview passages; 9.0.319 and 8.0.426 where behaviour differs

.NET 8 (LTS) and .NET 9 (STS) both reach end of support on 2026-11-10.

MSBuild

18.9.15, the version inside SDK 10.0.402

18.11 (Visual Studio 2026 18.11.1; GitHub release v18.11.0); 18.12 preview inside SDK 11 RC 2

There is no "what’s new in MSBuild 18" page; the changes are in the GitHub releases and the SDK what’s-new pages.

NuGet

7.9.0 (SDK 10.0.400 and later; nuget.exe 7.9.0, 2026-08-11)

7.10.0 (Visual Studio 2026 18.10 only); 8.0 prerelease inside SDK 11 RC 2

NuGet releases with each SDK feature band; there are no 7.1 and 7.2 release-note pages.

Visual Studio

2026 18.11.1 (2026-10-20)

Used only in the Visual Studio, Package Manager Console and msbuild.exe passages, which are not run here.

Publishing tools

Microsoft.SourceLink.* 10.0.402 (built into the SDK), Microsoft.DotNet.ApiCompat.Tool 10.0.402, sign 0.9.1-beta.26475.3 (beta), MinVer 8.0.0, Nerdbank.GitVersioning 3.10.94, NuGet.Server 3.4.3, BaGetter 1.6.5

MinVer, Nerdbank.GitVersioning and BaGetter are third-party; each appears in one worked example only.

CI actions

actions/setup-dotnet v6.0.0, NuGet/login v1.2.0 (major tag v1), NuGet/setup-nuget v4.0

Some learn.microsoft.com pages still show setup-dotnet@v3; these pages use v6.

nuget.org policy

API keys expire after at most 30 days (since 2026-08-17); older keys expire on 2026-11-01

Trusted Publishing (announced 2025-09-22)

Announced on the NuGet blog; the API key documentation still describes 365-day keys.

The running example: Ledgerline

Almost every example in the section uses one original repository, Ledgerline, a small library for double-entry bookkeeping ledgers. It reads a CSV journal (date,entry,account,debit,credit,memo), checks that every entry balances and exports a trial balance per account as JSON. No package named Ledgerline exists on nuget.org, and the examples never push one there: they publish to a folder feed (./artifacts/feed) and to a BaGetter server running in a container on http://localhost:5555.

ledgerline/
├── Ledgerline.slnx              solution (XML format, the .NET 10 default)
├── global.json                  pins SDK 10.0.402, selects the MTP test runner
├── nuget.config                 nuget.org + the local feeds, with package source mapping
├── Directory.Build.props        shared properties (Nullable, TreatWarningsAsErrors, package metadata)
├── Directory.Build.targets      packs README.md and icon.png into every packable project
├── Directory.Packages.props     Central Package Management: every package version in one place
├── .editorconfig  README.md  LICENSE  icon.png  CHANGELOG.md
├── src/
│   ├── Ledgerline/              the library: net10.0;net8.0;netstandard2.0
│   ├── Ledgerline.Build/        an MSBuild task (ValidateLedger) + buildTransitive targets
│   ├── Ledgerline.Cli/          a .NET tool (command: ledgerline)
│   └── Ledgerline.Templates/    a template package (dotnet new ledgerline-app)
├── tests/Ledgerline.Tests/      xUnit v3 tests (VSTest and Microsoft.Testing.Platform)
└── samples/
    ├── Ledgerline.Report/       console app that consumes Ledgerline from the local feed
    └── quick-ledger.cs          a file-based app (#:package directive)

Building the consumer app shows all three tools at work in a few lines: NuGet restores Ledgerline and Ledgerline.Build from the local feed, MSBuild runs the LedgerlineValidateJournals target that the Ledgerline.Build package added to the build, and the compiler writes the app.

cd ledgerline/samples/Ledgerline.Report
dotnet build -tl:off
dotnet run --no-build -- journal.ledger.csv
  Determining projects to restore...
  Restored ~/ledgerline/samples/Ledgerline.Report/Ledgerline.Report.csproj (in 355 ms).
  Ledgerline: 4 journal lines balance.
  Ledgerline.Report -> ~/ledgerline/samples/Ledgerline.Report/bin/Debug/net10.0/Ledgerline.Report.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.03
[
  {
    "Account": "1000-Cash",
    "Debit": 500.00,
    "Credit": 120.00,
    "Balance": 380.00
  },
  …
]

-tl:off turns off the Terminal Logger (the default console logger since .NET 9), whose live, redrawn output does not survive copying into a page; the section uses it, or -v:n, wherever output is shown.

Reading path

The section has five groups. Read the shared pages first; the other four can be read in any order.

Shared foundations (this group) — the concepts that cut across the three tools:

MSBuild — the engine: project file anatomy, properties, items, functions, conditions, targets, incremental builds, tasks, imports, customisation, the command line, binary logs, parallel and graph builds, BuildCheck, the API and troubleshooting.

.NET SDK & dotnet CLI — the driver: installing and selecting SDKs, every dotnet command (including file-based apps, dnx and the .NET 10 noun-first commands), templates, the SDK property reference, environment variables and SDK errors.

NuGet — the package manager from the consumer’s side: versions and ranges, dependency resolution, PackageReference, Central Package Management, lock files, nuget.config, source mapping, restore, auditing, signatures, authenticated feeds, the commands and the server API.

Publishing & Distributing Libraries — the life of a library from design to a published, maintained package: metadata, dotnet pack, layout, versioning, symbols and Source Link, package validation, signing, tools and templates, nuget.org, Trusted Publishing, private feeds and CI release workflows.

The sources consulted for every page are listed in the C# Reference bibliography; each page also ends with its own references.