Select the .NET version to use

This article explains the policies used by the .NET tools, SDK, and runtime for selecting versions. These policies provide a balance between running applications using the specified versions and enabling ease of upgrading both developer and end-user machines. These policies perform the following actions:

  • Easy and efficient deployment of .NET, including security and reliability updates.
  • Use the latest tools and commands independent of target runtime.

Version selection occurs:

The rest of this document examines those four scenarios.

The SDK uses the latest installed version

SDK commands include dotnet new and dotnet run. The .NET CLI must choose an SDK version for every dotnet command. It uses the latest SDK installed on the machine by default, even if:

  • The project targets an earlier version of the .NET runtime.
  • The latest version of the .NET SDK is a preview version.

You can take advantage of the latest SDK features and improvements while targeting earlier .NET runtime versions. You can target multiple runtime versions of .NET on different projects, using the same SDK tools for all projects.

On rare occasions, you may need to use an earlier version of the SDK. You specify that version in a global.json file. The "use latest" policy means you only use global.json to specify a .NET SDK version earlier than the latest installed version.

global.json can be placed anywhere in the file hierarchy. The CLI searches upward from the project directory for the first global.json it finds. You control which projects a given global.json applies to by its place in the file system. The .NET CLI searches for a global.json file iteratively navigating the path upward from the current working directory. The first global.json file found specifies the version used. If that SDK version is installed, that version is used. If the SDK specified in the global.json is not found, the .NET CLI uses matching rules to select a compatible SDK, or fails if none is found.

The following example shows the global.json syntax:

  "sdk": {
    "version": "3.0.0"

The process for selecting an SDK version is:

  1. dotnet searches for a global.json file iteratively reverse-navigating the path upward from the current working directory.
  2. dotnet uses the SDK specified in the first global.json found.
  3. dotnet uses the latest installed SDK if no global.json is found.

You can learn more about selecting an SDK version in the Matching rules section of the article on global.json.

Target Framework Monikers define build time APIs

You build your project against APIs defined in a Target Framework Moniker (TFM). You specify the target framework in the project file. Set the TargetFramework element in your project file as shown in the following example:


You may build your project against multiple TFMs. Setting multiple target frameworks is more common for libraries but can be done with applications as well. You specify a TargetFrameworks property (plural of TargetFramework). The target frameworks are semicolon-delimited as shown in the following example:


A given SDK supports a fixed set of frameworks, capped to the target framework of the runtime it ships with. For example, the .NET Core 3.1 SDK includes the .NET Core 3.1 runtime, which is an implementation of the netcoreapp3.0 target framework. The .NET Core 3.1 SDK supports netcoreapp2.1, netcoreapp2.2, netcoreapp3.0, but not net5.0 (or higher). You install the .NET 5.0 SDK to build for net5.0.

.NET Standard target frameworks are also capped to the target framework of the runtime the SDK ships with. The .NET 5.0 SDK is capped to netstandard2.1. For more information, see .NET Standard.

Framework-dependent apps roll forward

When you run an application from source with dotnet run, from a framework-dependent deployment with dotnet myapp.dll, or from a framework-dependent executable with myapp.exe, the dotnet executable is the host for the application.

The host chooses the latest patch version installed on the machine. For example, if you specified netcoreapp3.0 in your project file, and 3.0.2 is the latest .NET runtime installed, the 3.0.2 runtime is used.

If no acceptable 3.0.* version is found, a new 3.* version is used. For example, if you specified netcoreapp3.0 and only 3.1.0 is installed, the application runs using the 3.1.0 runtime. This behavior is referred to as "minor version roll-forward." Lower versions also won't be considered. When no acceptable runtime is installed, the application won't run.

A few usage examples demonstrate the behavior, if you target 3.0:

  • ✔️ 3.0 is specified. 3.0.3 is the highest patch version installed. 3.0.3 is used.
  • ❌ 3.0 is specified. No 3.0.* versions are installed. 2.1.1 is the highest runtime installed. An error message is displayed.
  • ✔️ 3.0 is specified. No 3.0.* versions are installed. 3.1.0 is the highest runtime version installed. 3.1.0 is used.
  • ❌ 2.0 is specified. No 2.x versions are installed. 3.0.0 is the highest runtime installed. An error message is displayed.

Minor version roll-forward has one side-effect that may affect end users. Consider the following scenario:

  1. The application specifies that 3.0 is required.
  2. When run, version 3.0.* is not installed, however, 3.1.0 is. Version 3.1.0 will be used.
  3. Later, the user installs 3.0.3 and runs the application again, 3.0.3 will now be used.

It's possible that 3.0.3 and 3.1.0 behave differently, particularly for scenarios like serializing binary data.

Self-contained deployments include the selected runtime

You can publish an application as a self-contained distribution. This approach bundles the .NET runtime and libraries with your application. Self-contained deployments don't have a dependency on runtime environments. Runtime version selection occurs at publishing time, not run time.

The publishing process selects the latest patch version of the given runtime family. For example, dotnet publish will select .NET Core 3.0.3 if it is the latest patch version in the .NET Core 3.0 runtime family. The target framework (including the latest installed security patches) is packaged with the application.

It's an error if the minimum version specified for an application isn't satisfied. dotnet publish binds to the latest runtime patch version (within a given major.minor version family). dotnet publish doesn't support the roll-forward semantics of dotnet run. For more information about patches and self-contained deployments, see the article on runtime patch selection in deploying .NET applications.

Self-contained deployments may require a specific patch version. You can override the minimum runtime patch version (to higher or lower versions) in the project file, as shown in the following example:


The RuntimeFrameworkVersion element overrides the default version policy. For self-contained deployments, the RuntimeFrameworkVersion specifies the exact runtime framework version. For framework-dependent applications, the RuntimeFrameworkVersion specifies the minimum required runtime framework version.

See also