Analyze an MSBuild solution, solution filter, or Build.proj that schedules multiple project files. USE FOR: measured idle worker nodes, `-m` that does not scale, a serial ProjectReference critical path, graph builds, or an MSBuild task that builds a Projects list. Requires at least two distinct project files whose scheduling or throughput must be analyzed. DO NOT USE for non-MSBuild build systems.
Start a fresh conversation. Replace the highlighted placeholders.
Use build-parallelism to analyze [MSBuild solution or Build.proj] containing at least two projects, identify actual worker-node use and the project critical path, and recommend only proven-safe dependency or scheduling improvements.
Required inputs
[MSBuild solution or Build.proj]
User-approved starter prompt based on a pinned source version; check current skill requirements before running. Task evidence ↗
SKILL.md
name: build-parallelismdescription: "Analyze an MSBuild solution, solution filter, or Build.proj that schedules multiple project files. USE FOR: measured idle worker nodes, `-m` that does not scale, a serial ProjectReference critical path, graph builds, or an MSBuild task that builds a Projects list. Requires at least two distinct project files whose scheduling or throughput must be analyzed. DO NOT USE for non-MSBuild build systems."license: MIT
Diagnose a slow parallel build (start here)
Work this checklist in order — it targets the usual root cause (a serial
dependency chain that no number of cores can parallelize):
Check how many worker nodes actually built the solution. Capture a
binlog with dotnet build /bl:{} (PowerShell: dotnet build '-bl:{}') and
inspect the node timeline to see whether more than one node ran. Every
dotnet CLI command built on the SDK's MSBuild-forwarding path (build,
msbuild, test, pack, publish, etc.) enables /maxcpucount (multiple
nodes) by default; -m:1 forces a single node. A direct MSBuild.exe
invocation is sequential by default, so pass -m explicitly to enable
parallel worker nodes there.
Find the critical path. From the binlog, read per-project timings and the
node timeline. If total build time ≈ the sum of the projects on one
dependency chain, that chain — not CPU count — is the bottleneck.
Name the chain explicitly, e.g. Core → Api → Web → Tests. A long serial
chain stays serial no matter how large -m is, because each project waits on
its predecessor.
Look for unnecessary ProjectReference edges that lengthen the chain — a
reference that only needs build order (not the output assembly), or one that
could be a PackageReference, forces serialization it doesn't need.
Recommend flattening: break false dependencies so independent projects
build concurrently, and consider /graph for better scheduling.
MSBuild Parallelism Model
/maxcpucount (or -m): number of worker nodes (processes)
Every dotnet CLI command (build, msbuild, test, pack, publish,
etc.) passes /maxcpucount by default via the SDK's shared MSBuild-forwarding
path; -m:1 overrides it with one node
A direct MSBuild.exe invocation is sequential by default and requires an
explicit -m
Recommended: -m without a number = use all logical processors
Each node builds one project at a time
Projects are scheduled based on dependency graph
Project Dependency Graph
MSBuild builds projects in dependency order (topological sort)
Critical path: longest chain of dependent projects determines minimum build time
Bottleneck: if project A depends on B, C, D and B takes 60s while C and D take 5s, B is the bottleneck
Diagnosis: replay binlog to diagnostic log with performancesummary and check Project Performance Summary — shows per-project time; grep for node.*assigned to check scheduling