Skills build-parallelism
Guide for optimizing MSBuild build parallelism and multi-project scheduling. Only activate in MSBuild/.NET build context. USE FOR: builds not utilizing all CPU cores, speeding up multi-project solutions, evaluating graph build mode (/graph), build time not improving with -m flag, understanding project dependency topology. Note: /maxcpucount default is 1 (sequential) — always use -m for parallel builds. Covers /maxcpucount, graph build for better scheduling and isolation, BuildInParallel on MSBuild task, reducing unnecessary ProjectReferences, solution filters (.slnf) for building subsets. DO NOT USE FOR: single-project builds, incremental build issues (use incremental-build), compilation slowness within a project (use build-perf-diagnostics), non-MSBuild build systems. INVOKES: dotnet build -m, dotnet build /graph, binlog analysis.
git clone https://github.com/dotnet/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/dotnet/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/dotnet-msbuild/skills/build-parallelism" ~/.claude/skills/dotnet-skills-build-parallelism && rm -rf "$T"
plugins/dotnet-msbuild/skills/build-parallelism/SKILL.mdMSBuild Parallelism Model
(or/maxcpucount
): number of worker nodes (processes)-m- Default: 1 node (sequential!). Always use
for parallel builds-m - Recommended:
without a number = use all logical processors-m - 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
and check Project Performance Summary — shows per-project time; grep forperformancesummary
to check schedulingnode.*assigned - Wide graphs (many independent projects) parallelize well; deep graphs (long chains) don't
Graph Build Mode (/graph
)
/graph
ordotnet build /graphmsbuild /graph- What it changes: MSBuild constructs the full project dependency graph BEFORE building
- Benefits: better scheduling, avoids redundant evaluations, enables isolated builds
- Limitations: all projects must use
(no programmatic MSBuild task references)<ProjectReference> - When to use: large solutions with many projects, CI builds
- When NOT to use: projects that dynamically discover references at build time
Optimizing Project References
- Reduce unnecessary
— each adds to the dependency chain<ProjectReference> - Use
to avoid extra evaluations<ProjectReference ... SkipGetTargetFrameworkProperties="true">
for build-order-only dependencies<ProjectReference ... ReferenceOutputAssembly="false">- Consider if a ProjectReference should be a PackageReference instead (pre-built NuGet)
- Use
(solution filters
) to build subsets of the solution.slnf
BuildInParallel
in custom targets<MSBuild Projects="@(ProjectsToBuild)" BuildInParallel="true" />- Without
, MSBuild task batches projects sequentiallyBuildInParallel="true" - Ensure
> 1 for this to have effect/maxcpucount
Multi-threaded MSBuild Tasks
- Individual tasks can run multi-threaded within a single project build
- Tasks implementing
can run on multiple threadsIMultiThreadableTask - Tasks must declare thread-safety via
[MSBuildMultiThreadableTask]
Analyzing Parallelism with Binlog
Step-by-step:
- Replay the binlog:
dotnet msbuild build.binlog -noconlog -fl -flp:v=diag;logfile=full.log;performancesummary - Check Project Performance Summary at the end of
full.log - Ideal: build time should be much less than sum of project times (parallelism)
- If build time ≈ sum of project times: too many serial dependencies, or one slow project blocking others
→ find the bottleneck targetsgrep 'Target Performance Summary' -A 30 full.log- Consider splitting large projects or optimizing the critical path
CI/CD Parallelism Tips
- Use
in CI (many CI runners have multiple cores)-m - Consider splitting solution into build stages for extreme parallelism
- Use build caching (NuGet lock files, deterministic builds) to avoid rebuilding unchanged projects
works well with structured CI pipelinesdotnet build /graph