Skip to content

msbuild-props: TargetFramework/TargetFrameworks precedence note is backwards #55612

Description

@MaxByrneFBG

Description

The note under TargetFrameworks states:

If TargetFrameworks (plural) is specified, TargetFramework (singular) is ignored.

The actual SDK behavior is the opposite: a non-empty TargetFramework (singular) wins, and TargetFrameworks (plural) is ignored.

Evidence from the SDK source

Cross-targeting is only engaged when the singular property is empty — src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.targets:

<PropertyGroup Condition="'$(TargetFrameworks)' != '' and '$(TargetFramework)' == ''">
  <IsCrossTargetingBuild>true</IsCrossTargetingBuild>
</PropertyGroup>

If TargetFramework is set (from the csproj, Directory.Build.props, or anywhere else), the project builds as a plain single-target project regardless of TargetFrameworks.

Repro

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <TargetFrameworks>net8.0;net10.0</TargetFrameworks>
  </PropertyGroup>
</Project>

dotnet build -c Release (SDK 10.0.111) produces only bin/Release/net8.0 - the plural property is ignored. Per the current doc text you would expect both net8.0 and net10.0 outputs.

Why it matters

The precedence determines behavior when the two properties are layered (e.g. Directory.Build.props sets one and a csproj sets the other) - a common pattern during incremental multi-targeting migrations. The current text leads reviewers and AI tooling to flag correct project files as broken (and vice versa).

Suggested correction

If TargetFramework (singular) is specified, TargetFrameworks (plural) is ignored and the project builds as a single-target project.


Document Details

Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

Metadata

Metadata

Assignees

Type

No type

Projects

Status
🔖 Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions