documentation/release.md
This is a description of the steps required to release MSBuild. The complete operational checklist is in release-checklist.md.
MSBuild ships in both Visual Studio (monthly) and the .NET SDK (quarterly). Each monthly VS release gets its own vs* branch, final branding, and VS insertion. The checklist is organized into 6 timeline-gated phases (0–5) with explicit triggers and ordering.
MSBuild is a component inserted into Visual Studio. VS ships monthly; MSBuild must branch and prepare its bits before VS is ready to take them.
Stabilize-Release.ps1The VS insertion pipeline controls the routing:
main → VS main (daily canary builds)vs* release branch → VS main (replaces main → main after branch snap)VS handles the progression from main → rel/insiders → rel/stable on its own schedule. MSBuild's responsibility is to have final-branded bits in VS main before INSIDERS_SNAP_DATE.
The AutoInsertTargetBranch mapping in azure-pipelines/vs-insertion.yml encodes which MSBuild branch maps to which VS branch.
To produce packages without a -prerelease suffix, we need to specify <DotNetFinalVersionKind>release</DotNetFinalVersionKind> (see the Arcade versioning docs). This is ideally done on the same line as the version specification so that it causes a Git merge conflict when merging to the next release's branch. See #6902 for an example.
Run scripts/Stabilize-Release.ps1 to automate this process. The script modifies eng/Versions.props to add DotNetFinalVersionKind and change PreReleaseVersionLabel from preview to servicing. Use -DryRun to preview changes before applying them.
As of #7018, MSBuild uses a Roslyn analyzer to ensure compatibility with assemblies compiled against older versions of MSBuild. The workflow of the analyzer is:
PublicAPI.Unshipped.txt files updated.PublicAPI.Unshipped.txt.Unshipped public API to Shipped.That is a new step in our release process for each formal release (including patch releases if they change API surface).
Update major version of VS in