Environment Variables, Completion and Telemetry

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.

Besides its commands, the dotnet CLI is configured by environment variables, offers shell completion, reports telemetry, and can describe itself as JSON for other tools. This page covers those parts with .NET SDK 10.0.402 on Linux, showing the variables that change behaviour in practice.

Environment variables

Variable Effect

DOTNET_ROOT (and DOTNET_ROOT_X64, …)

Where an apphost (./MyApp) and other hosts look for the runtime when it is not in the default location.

DOTNET_NOLOGO

1/true: no welcome and telemetry banner on first run.

DOTNET_CLI_TELEMETRY_OPTOUT

1/true: send no telemetry.

DOTNET_SKIP_FIRST_TIME_EXPERIENCE

Historical; no longer supported since .NET Core 3.0.

DOTNET_ROLL_FORWARD

Runtime roll-forward policy for apps started from this environment (Minor, Major, LatestMajor, Disable, …).

DOTNET_CLI_ENABLEAOT

Turn the CLI’s native (AOT-compiled) fast path for common commands on or off.

DOTNET_CLI_USE_MSBUILD_SERVER

Use MSBuild Server (opt-in on .NET 10, on by default in .NET 11).

NUGET_PACKAGES

The NuGet global-packages folder (Global Packages and Cache Folders).

DOTNET_CLI_UI_LANGUAGE

The CLI’s display language.

DOTNET_ROLL_FORWARD and DOTNET_ROOT

An application built for net7.0 (out of support, so the build warns NETSDK1138) on a machine with the .NET 8, 9 and 10 runtimes, where .NET is installed in a user folder rather than /usr/share/dotnet:

./bin/Debug/net7.0/Rf
DOTNET_ROLL_FORWARD=Major ./bin/Debug/net7.0/Rf
env -u DOTNET_ROOT DOTNET_ROLL_FORWARD=Major ./bin/Debug/net7.0/Rf
You must install or update .NET to run this application.

App: ~/rf/bin/Debug/net7.0/Rf
Architecture: x64
Framework: 'Microsoft.NETCore.App', version '7.0.0' (x64)
.NET location: ~/.dotnet

The following frameworks were found:
…
Running on .NET 8.0.32
You must install .NET to run this application.

App: ~/rf/bin/Debug/net7.0/Rf
Architecture: x64
App host version: 7.0.20
.NET location: Not found
  • The default policy, Minor, never moves an app to a new major version, so the .NET 7 app did not start.

  • DOTNET_ROLL_FORWARD=Major let it run on the lowest higher major runtime installed — 8.0.32, not 10. Use it to keep an old tool running, not as a deployment strategy; the app should be retargeted.

  • Without DOTNET_ROOT, the apphost looked only in the default locations and found no .NET at all. A user-folder installation (the dotnet-install script, CI) needs DOTNET_ROOT for apphosts; dotnet app.dll does not, because the muxer knows where it is.

The first run

The first command on a new user profile prints a banner and creates the ASP.NET Core development certificate:

Welcome to .NET 10.0!
---------------------
SDK Version: 10.0.402

Telemetry
---------
The .NET tools collect usage data in order to help us improve your experience. It is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell.

Read more about .NET CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry

----------------
Installed an ASP.NET Core HTTPS development certificate.
To trust the certificate, run 'dotnet dev-certs https --trust'
Learn about HTTPS: https://aka.ms/dotnet-https

In CI, set DOTNET_NOLOGO=1 and DOTNET_CLI_TELEMETRY_OPTOUT=1 for the whole job, so the banner does not appear in logs and nothing is sent (CI Builds and Caching).

Telemetry

The CLI sends usage data for each SDK command (dotnet build, dotnet run, …; running an app with dotnet app.dll sends nothing): the command and the options used, the SDK and OS versions, whether global.json was valid, MSBuild task-host statistics, hashed values of selected MSBuild properties, and exception information when the CLI crashes. The installer also sends one entry on a successful installation. Two more facts are derived from environment variables whose values are not collected:

  • CI detection — whether well-known CI variables (TF_BUILD, GITHUB_ACTIONS, CI, …) are set.

  • LLM detection — whether the CLI was started by an AI agent, from GITHUB_COPILOT_CLI_MODE (copilot), CLAUDECODE (claude), CURSOR_EDITOR (cursor) or GEMINI_CLI (gemini); several matches are concatenated.

Opt out with DOTNET_CLI_TELEMETRY_OPTOUT=1 (or true), set before the first command. In .NET 11 the CLI moves its telemetry pipeline to OpenTelemetry; the opt-out variable is unchanged.

Tab completion

NET 10 generates native completion scripts — no dotnet complete call per keystroke:
dotnet completions script bash | head -9
dotnet completions script bash | wc -l
#!/usr/bin/env bash
_dotnet() {

    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    COMPREPLY=()

    opts="build build-server clean format fsi msbuild new nuget pack package project publish reference restore run solution store test tool vstest help sdk workload completions --help --diagnostics --version --info --list-sdks --list-runtimes"
2347

The shells are bash, fish, nushell, pwsh and zsh (SDK 10.0.402 already generated fish completions, which the .NET 11 what’s-new page lists as new). Add eval "$(dotnet completions script bash)" to ~/.bashrc, or the equivalent for the shell. The older dynamic scripts, which call dotnet complete and work with every SDK version, remain available for shells and versions without native scripts.

--cli-schema

Every command describes its arguments and options as JSON with --cli-schema (.NET 10), for tools, agents and IDEs that build dotnet command lines:

dotnet build --cli-schema | head -20
{
  "name": "build",
  "version": "10.0.402",
  "description": ".NET Builder",
  "hidden": false,
  "arguments": {
    "PROJECT | SOLUTION | FILE": {
      "description": "The project or solution or C# (file-based program) file to operate on. If a file is not specified, the command will search the current directory for a project or solution.",
      "order": 0,
      "hidden": false,
      "valueType": "System.String[]",
      "hasDefaultValue": false,
      "arity": {
        "minimum": 0
      }
    }
  },
  "options": {
    "--arch": {

dotnet build declared 33 options. Pass-through MSBuild switches (-p, -bl) are not in the schema.

Elevated access

Only a few commands are meant to run elevated (sudo, an administrator prompt): installing or running tools that need it (dotnet tool install --tool-path into a system folder), dotnet run --no-build, and the uninstall tool. Commands that run MSBuild — restore, build, run — should not be run elevated: they write obj, bin and the NuGet caches, and switching between root and a normal account leaves files the normal account cannot overwrite. Running everything as root, as in a container, is fine as long as nothing switches back.

Common mistakes

  • Apphosts failing in CI with "You must install .NET" — export DOTNET_ROOT for user-folder installs.

  • DOTNET_ROLL_FORWARD=Major set globally — every old app silently runs on a newer major runtime.

  • Opting out of telemetry after the first command — set the variable before it.

  • sudo dotnet build — root-owned obj folders and caches.