Target frameworks in SDK-style projects
When you target a framework in an app or library, you're specifying the set of APIs that you'd like to make available to the app or library. You specify the target framework in your project file using a target framework moniker (TFM).
An app or library can target a version of .NET Standard. .NET Standard versions represent standardized sets of APIs across all .NET implementations. For example, a library can target .NET Standard 1.6 and gain access to APIs that function across .NET Core and .NET Framework using the same codebase.
An app or library can also target a specific .NET implementation to gain access to implementation-specific APIs. For example, an app that targets Xamarin.iOS (for example, Xamarin.iOS10
) has access to Xamarin-provided iOS API wrappers for iOS 10, or an app that targets Universal Windows Platform (UWP, uap10.0
) has access to APIs that compile for devices that run Windows 10.
For some target frameworks, such as .NET Framework, the APIs are defined by the assemblies that the framework installs on a system and may include application framework APIs (for example, ASP.NET).
For package-based target frameworks (for example, .NET 5+, .NET Core, and .NET Standard), the APIs are defined by the NuGet packages included in the app or library.
Latest versions
The following table defines the most common target frameworks, how they're referenced, and which version of .NET Standard they implement. These target framework versions are the latest stable versions. Prerelease versions aren't shown. A target framework moniker (TFM) is a standardized token format for specifying the target framework of a .NET app or library.
Target framework | Latest stable version |
Target framework moniker (TFM) | Implemented .NET Standard version |
---|---|---|---|
.NET 8 | 8 | net8.0 | 2.1 |
.NET 7 | 7 | net7.0 | 2.1 |
.NET 6 | 6 | net6.0 | 2.1 |
.NET 5 | 5 | net5.0 | 2.1 |
.NET Standard | 2.1 | netstandard2.1 | N/A |
.NET Core | 3.1 | netcoreapp3.1 | 2.1 |
.NET Framework | 4.8.1 | net481 | 2.0 |
Supported target frameworks
A target framework is typically referenced by a TFM. The following table shows the target frameworks supported by the .NET SDK and the NuGet client. Equivalents are shown within brackets. For example, win81
is an equivalent TFM to netcore451
.
Target Framework | TFM |
---|---|
.NET 5+ (and .NET Core) | netcoreapp1.0 netcoreapp1.1 netcoreapp2.0 netcoreapp2.1 netcoreapp2.2 netcoreapp3.0 netcoreapp3.1 net5.0* net6.0* net7.0* net8.0* |
.NET Standard | netstandard1.0 netstandard1.1 netstandard1.2 netstandard1.3 netstandard1.4 netstandard1.5 netstandard1.6 netstandard2.0 netstandard2.1 |
.NET Framework | net11 net20 net35 net40 net403 net45 net451 net452 net46 net461 net462 net47 net471 net472 net48 net481 |
Windows Store | netcore [netcore45] netcore45 [win] [win8] netcore451 [win81] |
.NET Micro Framework | netmf |
Silverlight | sl4 sl5 |
Windows Phone | wp [wp7] wp7 wp75 wp8 wp81 wpa81 |
Universal Windows Platform | uap [uap10.0] uap10.0 [win10] [netcore50] |
* .NET 5 and later TFMs include some operating system-specific variations. For more information, see the following section, .NET 5+ OS-specific TFMs.
.NET 5+ OS-specific TFMs
The net5.0
, net6.0
, net7.0
, and net8.0
TFMs include technologies that work across different platforms. Specifying an OS-specific TFM makes APIs that are specific to an operating system available to your app, for example, Windows Forms or iOS bindings. OS-specific TFMs also inherit every API available to their base TFM, for example, the net6.0
TFM.
.NET 5 introduced the net5.0-windows
OS-specific TFM, which includes Windows-specific bindings for WinForms, WPF, and UWP APIs. .NET 6 and later versions have additional OS-specific TFMs, for example, net6.0-ios
.
The following table shows the compatibility of the .NET 5+ TFMs.
TFM | Compatible with |
---|---|
net5.0 |
net1..4 (with NU1701 warning) netcoreapp1..3.1 (warning when WinForms or WPF is referenced) netstandard1..2.1 |
net5.0-windows |
netcoreapp1..3.1 (plus everything else inherited from net5.0 ) |
net6.0 |
(Subsequent version of net5.0 ) |
net6.0-android |
xamarin.android (plus everything else inherited from net6.0 ) |
net6.0-ios |
Everything inherited from net6.0 |
net6.0-maccatalyst |
Everything inherited from net6.0 |
net6.0-macos |
Everything inherited from net6.0 |
net6.0-tvos |
Everything inherited from net6.0 |
net6.0-windows |
(Subsequent version of net5.0-windows ) |
net7.0 |
(Subsequent version of net6.0 ) |
net7.0-android |
(Subsequent version of net6.0-android ) |
net7.0-ios |
(Subsequent version of net6.0-ios ) |
net7.0-maccatalyst |
(Subsequent version of net6.0-maccatalyst ) |
net7.0-macos |
(Subsequent version of net6.0-macos ) |
net7.0-tizen |
tizen40 (plus everything else inherited from net7.0 ) |
net7.0-tvos |
(Subsequent version of net6.0-tvos ) |
net7.0-windows |
(Subsequent version of net6.0-windows ) |
net8.0 |
(Subsequent version of net7.0 ) |
net8.0-android |
(Subsequent version of net7.0-android ) |
net8.0-browser |
Everything inherited from net8.0 |
net8.0-ios |
(Subsequent version of net7.0-ios ) |
net8.0-maccatalyst |
(Subsequent version of net7.0-maccatalyst ) |
net8.0-macos |
(Subsequent version of net7.0-macos ) |
net8.0-tizen |
(Subsequent version of net7.0-tizen ) |
net8.0-tvos |
(Subsequent version of net7.0-tvos ) |
net8.0-windows |
(Subsequent version of net7.0-windows ) |
To make your app portable across different platforms but still have access to OS-specific APIs, you can target multiple OS-specific TFMs and add platform guards around OS-specific API calls using #if
preprocessor directives. For a list of the available symbols, see Preprocessor symbols.
Suggested targets
Use these guidelines to determine which TFM to use in your app:
Apps that are portable to multiple platforms should target a base TFM, for example,
net8.0
. This includes most libraries but also ASP.NET Core and Entity Framework.Platform-specific libraries should target platform-specific flavors. For example, WinForms and WPF projects should target
net8.0-windows
.Cross-platform application models (Xamarin Forms, ASP.NET Core) and bridge packs (Xamarin Essentials) should at least target the base TFM, for example,
net8.0
, but might also target additional platform-specific flavors to light-up more APIs or features.
OS version in TFMs
You can also specify an optional OS version at the end of an OS-specific TFM, for example, net6.0-ios15.0
. The version indicates which APIs are available to your app or library. It doesn't control the OS version that your app or library supports at run time. It's used to select the reference assemblies that your project compiles against, and to select assets from NuGet packages. Think of this version as the "platform version" or "OS API version" to disambiguate it from the run-time OS version.
When an OS-specific TFM doesn't specify the platform version explicitly, it has an implied value that can be inferred from the base TFM and platform name. For example, the default platform value for Android in .NET 6 is 31.0
, which means that net6.0-android
is shorthand for the canonical net6.0-android31.0
TFM. The implied platform version for a newer base TFM may be higher, for example, a future net8.0-android
TFM could map to net8.0-android34.0
. The shorthand form is intended for use in project files only, and is expanded to the canonical form by the .NET SDK's MSBuild targets before being passed to other tools, such as NuGet.
The following table shows the default target platform values (TPV) for each .NET release.
.NET version | Android | iOS | Mac Catalyst | macOS | tvOS | Tizen | Windows |
---|---|---|---|---|---|---|---|
.NET 6 | 31.0 | 15.0 | 15.0 | 12.0 | 15.1 | - | 7.0 |
.NET 7 | 33.0 | 16.1 | 16.1 | 13.0 | 16.1 | 7.0 | 7.0 |
.NET 8 | 34.0 | 17.2 | 17.2 | 14.2 | 17.1 | 8.0 | 7.0 |
Note
On Apple platforms (iOS, macOS, tvOS, and Mac Catalyst) in .NET 8 and earlier, the default TPV is the latest supported version in the currently installed workload. That means that updating the iOS workload in .NET 8, for example, might result in a higher default TPV, if support for a new version of iOS has been added in that workload. In the preceding table, the default TPV is the one in the initial release for the stated .NET version.
Starting in .NET 9, this special behavior only applies to executable projects. The default TPV for library projects now stays the same for the entirety of a major .NET release, like all other platforms.
The .NET SDK is designed to be able to support newly released APIs for an individual platform without a new version of the base TFM. This enables you to access platform-specific functionality without waiting for a major release of .NET. You can gain access to these newly released APIs by incrementing the platform version in the TFM. For example, if the Android platform added API level 32 APIs in a .NET 6.0.x SDK update, you could access them by using the TFM net6.0-android32.0
.
Precedence
If your app references a package that has multiple assets for different TFMs, the assets that are closer in version number are preferred. For example, if your app targets net6.0-ios
and the package offers assets for net6.0
and net5.0-ios
, the net6.0
assets are used. For more information, see Precedences.
Support older OS versions
Although a platform-specific app or library is compiled against APIs from a specific version of that OS, you can make it compatible with earlier OS versions by adding the SupportedOSPlatformVersion
property to your project file. The SupportedOSPlatformVersion
property indicates the minimum OS version required to run your app or library. If you don't explicitly specify this minimum run-time OS version in the project, it defaults to the platform version from the TFM.
For your app to run correctly on an older OS version, it can't call APIs that don't exist on that version of the OS. However, you can add guards around calls to newer APIs so they are only called when running on a version of the OS that supports them. This pattern allows you to design your app or library to support running on older OS versions while taking advantage of newer OS functionality when running on newer OS versions.
The SupportedOSPlatformVersion
value (whether explicit or default) is used by the platform compatibility analyzer, which detects and warns about unguarded calls to newer APIs. It's burned into the project's compiled assembly as an UnsupportedOSPlatformAttribute assembly attribute, so that the platform compatibility analyzer can detect unguarded calls to that assembly's APIs from projects with a lower SupportedOSPlatformVersion
value. On some platforms, the SupportedOSPlatformVersion
value affects platform-specific app packaging and build processes, which is covered in the documentation for those platforms.
Here is an example excerpt of a project file that uses the TargetFramework
and SupportedOSPlatformVersion
MSBuild properties to specify that the app or library has access to iOS 15.0 APIs but supports running on iOS 13.0 and above:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-ios15.0</TargetFramework>
<SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
</PropertyGroup>
...
</Project>
How to specify a target framework
Target frameworks are specified in a project file. When a single target framework is specified, use the TargetFramework element. The following console app project file demonstrates how to target .NET 8:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
When you specify multiple target frameworks, you may conditionally reference assemblies for each target framework. In your code, you can conditionally compile against those assemblies by using preprocessor symbols with if-then-else logic.
The following library project targets APIs of .NET Standard (netstandard1.4
) and .NET Framework (net40
and net45
). Use the plural TargetFrameworks element with multiple target frameworks. The Condition
attributes include implementation-specific packages when the library is compiled for the two .NET Framework TFMs:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;net40;net45</TargetFrameworks>
</PropertyGroup>
<!-- Conditionally obtain references for the .NET Framework 4.0 target -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
<Reference Include="System.Net" />
</ItemGroup>
<!-- Conditionally obtain references for the .NET Framework 4.5 target -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System.Net.Http" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
</Project>
Within your library or app, you write conditional code using preprocessor directives to compile for each target framework:
public class MyClass
{
static void Main()
{
#if NET40
Console.WriteLine("Target framework: .NET Framework 4.0");
#elif NET45
Console.WriteLine("Target framework: .NET Framework 4.5");
#else
Console.WriteLine("Target framework: .NET Standard 1.4");
#endif
}
}
Preprocessor symbols
The build system is aware of preprocessor symbols representing the target frameworks shown in the Supported target framework versions table when you're using SDK-style projects. To convert a .NET Standard, .NET Core, or .NET 5+ TFM to a preprocessor symbol, replace dots and hyphens with an underscore, and change lowercase letters to uppercase (for example, the symbol for netstandard1.4
is NETSTANDARD1_4
).
You can disable generation of these symbols via the DisableImplicitFrameworkDefines
property. For more information about this property, see DisableImplicitFrameworkDefines.
The complete list of preprocessor symbols for .NET target frameworks is:
Target Frameworks | Symbols | Additional symbols (available in .NET 5+ SDKs) |
Platform symbols (available only when you specify an OS-specific TFM) |
---|---|---|---|
.NET Framework | NETFRAMEWORK , NET48 , NET472 , NET471 , NET47 , NET462 , NET461 , NET46 , NET452 , NET451 , NET45 , NET40 , NET35 , NET20 |
NET48_OR_GREATER , NET472_OR_GREATER , NET471_OR_GREATER , NET47_OR_GREATER , NET462_OR_GREATER , NET461_OR_GREATER , NET46_OR_GREATER , NET452_OR_GREATER , NET451_OR_GREATER , NET45_OR_GREATER , NET40_OR_GREATER , NET35_OR_GREATER , NET20_OR_GREATER |
|
.NET Standard | NETSTANDARD , NETSTANDARD2_1 , NETSTANDARD2_0 , NETSTANDARD1_6 , NETSTANDARD1_5 , NETSTANDARD1_4 , NETSTANDARD1_3 , NETSTANDARD1_2 , NETSTANDARD1_1 , NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER , NETSTANDARD2_0_OR_GREATER , NETSTANDARD1_6_OR_GREATER , NETSTANDARD1_5_OR_GREATER , NETSTANDARD1_4_OR_GREATER , NETSTANDARD1_3_OR_GREATER , NETSTANDARD1_2_OR_GREATER , NETSTANDARD1_1_OR_GREATER , NETSTANDARD1_0_OR_GREATER |
|
.NET 5+ (and .NET Core) | NET , NET8_0 , NET7_0 , NET6_0 , NET5_0 , NETCOREAPP , NETCOREAPP3_1 , NETCOREAPP3_0 , NETCOREAPP2_2 , NETCOREAPP2_1 , NETCOREAPP2_0 , NETCOREAPP1_1 , NETCOREAPP1_0 |
NET8_0_OR_GREATER , NET7_0_OR_GREATER , NET6_0_OR_GREATER , NET5_0_OR_GREATER , NETCOREAPP3_1_OR_GREATER , NETCOREAPP3_0_OR_GREATER , NETCOREAPP2_2_OR_GREATER , NETCOREAPP2_1_OR_GREATER , NETCOREAPP2_0_OR_GREATER , NETCOREAPP1_1_OR_GREATER , NETCOREAPP1_0_OR_GREATER |
ANDROID , BROWSER , IOS , MACCATALYST , MACOS , TVOS , WINDOWS ,[OS][version] (for example IOS15_1 ),[OS][version]_OR_GREATER (for example IOS15_1_OR_GREATER ) |
Note
- Versionless symbols are defined regardless of the version you're targeting.
- Version-specific symbols are only defined for the version you're targeting.
- The
<framework>_OR_GREATER
symbols are defined for the version you're targeting and all earlier versions. For example, if you're targeting .NET Framework 2.0, the following symbols are defined:NET20
,NET20_OR_GREATER
,NET11_OR_GREATER
, andNET10_OR_GREATER
. - The
NETSTANDARD<x>_<y>_OR_GREATER
symbols are only defined for .NET Standard targets, and not for targets that implement .NET Standard, such as .NET Core and .NET Framework. - These are different from the target framework monikers (TFMs) used by the MSBuild
TargetFramework
property and NuGet.
Deprecated target frameworks
The following target frameworks are deprecated. Packages that target these target frameworks should migrate to the indicated replacements.
Deprecated TFM | Replacement |
---|---|
aspnet50 aspnetcore50 dnxcore50 dnx dnx45 dnx451 dnx452 |
netcoreapp |
dotnet dotnet50 dotnet51 dotnet52 dotnet53 dotnet54 dotnet55 dotnet56 |
netstandard |
netcore50 | uap10.0 |
win | netcore45 |
win8 | netcore45 |
win81 | netcore451 |
win10 | uap10.0 |
winrt | netcore45 |