When working on multiple .NET projects, you may need different SDK versions on the same machine. One application might use .NET 8, while another project requires .NET 10. Installing both SDKs is usually straightforward, but problems can appear when the command line selects a different SDK than the one your project expects.
This can lead to build errors, unexpected behavior in CI/CD pipelines, or differences between a developer's machine and the build server.
The good news is that you do not need to uninstall one SDK every time you switch projects. The .NET CLI provides SDK selection rules, and a global.json file lets you control which SDK a project uses.
In this article, we will look at how to install multiple .NET SDK versions, select the right version for each project, troubleshoot common problems, and keep local development and automated builds consistent.
Understanding .NET SDKs and Runtimes
Before managing multiple versions, it helps to understand the difference between an SDK and a runtime.
The .NET SDK includes the tools needed to create, build, test, and publish applications. The .NET runtime provides the environment required to run a compiled application.
For example, you might install the .NET 8 SDK to build an application targeting .NET 8. You might also install the .NET 10 SDK to work on a newer project.
Installing an SDK does not mean every application automatically targets that SDK's corresponding framework. The target framework is defined separately in the project file.
Here is a simple comparison.
Feature | .NET SDK | .NET Runtime |
|---|
Build applications | Yes | No |
Create new projects | Yes | No |
Run compatible applications | Includes runtime components | Yes |
Select compiler and build tools | Yes | No |
Required on a typical build server | Yes | Not usually sufficient by itself |
To check which SDKs and runtimes are installed, open a terminal and run the following commands.
dotnet --list-sdks
dotnet --list-runtimes
dotnet --info
The first command lists installed SDK versions. The second shows installed runtimes, and the third displays additional information, including the SDK selected for the current directory.
Step 1: Install Multiple .NET SDK Versions
You can install multiple SDK versions side by side. The exact installation method depends on your operating system and development environment.
On Windows, you can install the required SDK versions using their official installers or an approved package manager. On Linux and macOS, use the appropriate installation packages or package manager for your distribution.
After installing the SDKs, verify that they are available.
dotnet --list-sdks
Example output:
8.0.408 [C:\Program Files\dotnet\sdk]
9.0.203 [C:\Program Files\dotnet\sdk]
10.0.100 [C:\Program Files\dotnet\sdk]
The versions shown above are illustrative. Your installed versions and paths may differ.
You can now use the same machine to work on projects that require different SDK versions.
One important point: installing an SDK does not automatically update the target framework of an existing project. A project targeting net8.0 continues to target that framework until you change its project configuration.
Step 2: Check Which SDK the .NET CLI Uses
When you run a command such as dotnet build, the CLI selects an SDK based on its SDK resolution rules.
Without a global.json file that selects another SDK, the CLI generally uses the latest applicable SDK installed on the machine.
Move to your project directory and run:
dotnet --version
This command displays the SDK selected for that directory.
For example, your machine might have SDKs 8, 9, and 10 installed. If the CLI selects SDK 10, a project targeting net8.0 may still build with that SDK, provided the project and its dependencies are compatible.
However, this is not always the behavior you want. A project may depend on a specific SDK feature or require the same SDK version used by the rest of the team.
That is where global.json becomes useful.
Step 3: Use global.json to Select an SDK Version
The global.json file allows you to specify which .NET SDK the CLI should use for a directory tree.
Create a file named global.json in your repository root.
For example, to select SDK 8.0.408, use the following configuration:
{
"sdk": {
"version": "8.0.408",
"rollForward": "latestPatch",
"allowPrerelease": false
}
}
Each setting has a specific purpose.
version specifies the requested SDK version.
rollForward controls which alternative SDK versions may be selected when the requested version is unavailable.
allowPrerelease prevents the CLI from selecting a prerelease SDK for this resolution.
The latestPatch setting allows the CLI to use a later patch version within the requested SDK feature band. It does not allow an arbitrary move to a newer major or minor SDK version.
For example, if the requested SDK is not installed but a permitted later patch version in the same feature band is available, the CLI can select that version. If no compatible SDK exists, the command can fail with an SDK resolution error.
The global.json file does not install the requested SDK. You must install a compatible SDK separately.
Where should global.json be placed?
A common repository structure looks like this:
MySolution/
├── global.json
├── MySolution.sln
├── src/
│ ├── WebApp/
│ │ └── WebApp.csproj
│ └── Worker/
│ └── Worker.csproj
└── tests/
└── WebApp.Tests/
└── WebApp.Tests.csproj
Placing global.json in the solution root makes SDK selection consistent for commands executed within that directory tree, unless another applicable configuration changes the resolution.
This is particularly helpful when a solution contains multiple projects that should use the same SDK.
Step 4: Understand SDK Roll-Forward Settings
The rollForward setting determines how flexible SDK selection can be.
Choosing the right value depends on whether your team requires an exact SDK version or can accept compatible updates.
Setting | Behavior | When to use it |
|---|
disable | Requires the exact requested SDK version | Strict SDK reproducibility |
patch | Allows a later patch within the same feature band | Controlled patch updates |
latestPatch
| Selects the latest applicable patch in the requested feature band | Most recent compatible patch |
minor
| Allows movement to a later minor version when necessary | Teams that accept minor SDK changes |
latestMinor
| Prefers the latest applicable minor SDK version | Teams that want newer minor releases |
major
| Allows movement to a later major version when necessary | Flexible development environments |
latestMajor
| Allows selection of the latest applicable major SDK version | Environments where broad SDK upgrades are acceptable |
These settings do not all provide the same level of control. For example, latestMajor can allow a much newer SDK than the version specified in global.json.
For a team project, avoid choosing a broad roll-forward policy simply to make a build error disappear. First determine whether the project is intended to use a particular SDK version.
Also remember that SDK selection rules can be affected by prerelease settings and the versions actually installed on the machine.
Step 5: Keep the Target Framework Separate from the SDK Version
One common source of confusion is treating the SDK version and target framework as the same thing.
Consider this project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
The TargetFramework property specifies that the application targets .NET 8.
The SDK selected by the CLI determines which build tools and SDK components are used. These are related, but they are separate settings.
For example, an installed .NET 10 SDK may be able to build a project targeting .NET 8 if the required targeting packs and dependencies are available. However, using a newer SDK does not automatically upgrade the application to .NET 10.
If you want to change the target framework, update the project file deliberately and verify that the application's dependencies and deployment environment support the new target.
Step 6: Use the Same SDK in CI/CD Pipelines
A project may build successfully on your laptop but fail in a CI/CD pipeline because the build agent has a different SDK installed.
The global.json file helps avoid this inconsistency, but it is not a replacement for installing the required SDK on the build agent.
For example, a pipeline can verify the selected SDK before building:
dotnet --version
dotnet --info
dotnet restore
dotnet build --no-restore --configuration Release
dotnet test --no-build --configuration Release
The commands above assume that the pipeline has already installed the required SDK and that the restore, build, and test steps are running from the intended repository directory.
The version check makes SDK selection visible in the build logs. This is useful when investigating differences between local builds and automated builds.
For stronger consistency, keep the following items aligned:
The SDK version specified in global.json.
The SDK installed on developer machines and build agents.
The target frameworks declared in project files.
The package versions and build configuration used by the pipeline.
If a build agent does not have a compatible SDK, install the required version rather than relying on an unrelated SDK to be selected.
Common Problems and How to Fix Them
The requested SDK was not found
You may see an error indicating that the requested SDK version could not be found.
Check the installed SDKs:
dotnet --list-sdks
Then inspect the version and rollForward properties in global.json. Install the required SDK or adjust the configuration to match your team's intended SDK policy.
The wrong SDK version is selected
Run the following commands from the project directory:
dotnet --version
dotnet --info
Check whether a global.json file exists in the repository or a parent directory. The CLI searches for an applicable file based on the current working directory, so running the same command from a different directory can produce a different result.
Also check which dotnet executable your terminal is using if multiple installations exist.
The SDK is installed, but the project still fails to build
An SDK selection problem is not the only possible cause of a build failure.
Check the target framework in the .csproj file, package compatibility, installed targeting packs, and the actual build error. A project may select the expected SDK and still fail because a dependency or project configuration is incompatible.
Visual Studio and the command line behave differently
Visual Studio and the command-line environment may use different SDK installations, settings, or working directories.
Confirm the selected SDK in the terminal and check the SDK support available in your installed Visual Studio version. Also verify that the solution is opened from the expected repository directory.
Do not assume that a successful command-line build guarantees the same result in every IDE configuration.
Best Practices for Managing Multiple SDK Versions
For a stable development environment, follow these practices:
Commit global.json to source control: This gives team members and build agents a shared SDK selection policy.
Use a deliberate roll-forward policy: Allow only the SDK updates your project can safely support.
Keep SDK and target framework settings separate: Update each one for its own purpose.
Verify SDK selection during troubleshooting: Run dotnet --version from the actual project directory.
Keep build agents up to date: Install the SDK versions required by your repositories.
Test SDK upgrades before adopting them: Build and test the solution before changing the shared SDK configuration.
Avoid unnecessary global changes: Do not uninstall SDKs simply because one project needs a different version.
Advantages and Disadvantages of Using Multiple SDK Versions
Advantages | Disadvantages |
|---|
Supports projects targeting different .NET versions | Requires more disk space |
Makes it easier to maintain older applications | SDK selection can confuse new developers |
Supports gradual framework upgrades | Build agents need the appropriate SDKs |
Allows teams to test new SDK versions without immediately upgrading every project | Incorrect configuration can cause build failures |
For most development teams maintaining more than one .NET application, these trade-offs are manageable. The key is to document the SDK requirements and make the selected version easy to verify.
Summary
Managing multiple .NET SDK versions on the same machine is straightforward once you understand SDK selection and target frameworks.
Install the SDK versions your projects need, use dotnet --list-sdks to verify the installation, and run dotnet --version from the project directory to check which SDK the CLI selects.
For team projects, commit a suitable global.json file and make sure CI/CD agents have a compatible SDK installed. Keep the SDK version separate from the project's target framework, and investigate build errors before changing version settings.
With these practices in place, you can work on older and newer .NET projects on the same machine without repeatedly uninstalling SDKs or introducing avoidable differences between development and build environments.
Join the conversation! Your thoughts help the community grow.