/build-perf-baseline
Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before/after measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output,
$ npx -y skills add dotnet/skills --skill build-perf-baseline --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/build-perf-baseline
Context preview
The summary Claude sees to decide when to auto-load this skill.
Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before/after measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output,
SKILL.md
build-perf-baseline.SKILL.mdname: build-perf-baseline
description: "Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before/after measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output, and dependency graph trimming. Start here before diving into build-perf-diagnostics, incremental-build, or build-parallelism. DO NOT USE FOR: non-MSBuild build systems, detailed bottleneck analysis (use build-perf-diagnostics after baselining)."
license: MIT
Build Performance Baseline & Optimization
Overview
Before optimizing a build, you need a **baseline**. Without measurements, optimization is guesswork. This skill covers how to establish baselines and apply systematic optimization techniques.
**Related skills:**
- `build-perf-diagnostics` — binlog-based bottleneck identification
- `incremental-build` — Inputs/Outputs and up-to-date checks
- `build-parallelism` — parallel and graph build tuning
- `eval-performance` — glob and import chain optimization
---
Step 1: Establish a Performance Baseline
Measure three scenarios to understand where time is spent:
Cold Build (First Build)
No previous build output exists. Measures the full end-to-end time including restore, compilation, and all targets.
# Clean everything first
dotnet clean
# Remove bin/obj to truly start fresh
Get-ChildItem -Recurse -Directory -Include bin,obj | Remove-Item -Recurse -Force
# OR on Linux/macOS:
# find . -type d \( -name bin -o -name obj \) -exec rm -rf {} +
# Measure cold build
dotnet build /bl:cold-build.binlog -mWarm Build (Incremental Build)
Build output exists, some files have changed. Measures how well incremental build works.
# Build once to populate outputs
dotnet build -m
# Make a small change (touch one .cs file)
# Then rebuild
dotnet build /bl:warm-build.binlog -m
No-Op Build (Nothing Changed)
Build output exists, nothing has changed. This should be nearly instant. If it's slow, incremental build is broken.
# Build once to populate outputs
dotnet build -m
# Rebuild immediately without changes
dotnet build /bl:noop-build.binlog -m
What Good Looks Like
| Scenario | Expected Behavior | |----------|------------------| | Cold build | Full compilation, all targets run. This is your absolute baseline | | Warm build | Only changed projects recompile. Time proportional to change scope | | No-op build | < 5 seconds for small repos, < 30 seconds for large repos. All compilation targets should report "Skipping target — all outputs up-to-date" |
**Red flags:**
- No-op build > 30 seconds → incremental build is broken (see `incremental-build` skill)
- Warm build recompiles everything → project dependency chain forces full rebuild
- Cold build has long restore → NuGet cache issues
Recording Baselines
Record baselines in a structured way before and after optimization:
| Scenario | Before | After | Improvement |
|-------------|---------|---------|-------------|
| Cold build | 2m 15s | | |
| Warm build | 1m 40s | | |
| No-op build | 45s | | |
---
Step 2: MSBuild Server (Persistent Build Process)
The MSBuild server keeps the build process alive between invocations, avoiding JIT compilation and assembly loading overhead on every build.
Enabling MSBuild Server
# Enabled by default in .NET 8+ but can be forced
dotnet build /p:UseSharedCompilation=true
The MSBuild server is started automatically and reused across builds. The compiler server (VBCSCompiler / `dotnet build-server`) is separate but complementary.
Managing the Build Server
# Check if the server is running
dotnet build-server status
# Shut down all build servers (useful when debugging)
dotnet build-server shutdown
When to Restart the Build Server
Restart after:
- Updating the .NET SDK
- Changing MSBuild tooling (custom tasks, props, targets)
- Debugging build infrastructure issues
- Seeing stale behavior in repeated builds
dotnet build-server shutdown
dotnet build
---
Step 3: Artifacts Output Layout
The `UseArtifactsOutput` feature (introduced in .NET 8) changes the output directory structure to avoid bin/obj clash issues and enable better caching.
Enabling Artifacts Output
<!-- Directory.Build.props -->
<PropertyGroup>
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>
Before vs After
# Traditional layout (before)
src/
MyLib/
bin/Debug/net8.0/MyLib.dll
obj/Debug/net8.0/...
MyApp/
bin/Debug/net8.0/MyApp.dll
# Artifacts layout (after)
artifacts/
bin/MyLib/debug/MyLib.dll
bin/MyApp/debug/MyApp.dll
obj/MyLib/debug/...
obj/MyApp/debug/...Benefits
- **No bin/obj clash**: Each project+configuration gets a unique path automatically
- **Easier to cache**: Single `artifacts/` directory to cache/restore in CI
- **Cleaner .gitignore**: Just ignore `artifacts/`
- **Multi-targeting safe**: Each TFM gets its own subdirectory
Customizing
<!-- Change the artifacts root -->
<PropertyGroup>
<ArtifactsPath>$(MSBuildThisFileDirectory)output</ArtifactsPath>
</PropertyGroup>
---
Step 4: Deterministic Builds
Deterministic builds produce byte-for-byte identical output given the same inputs. This is essential for build caching and reproducibility.
Enabling Deterministic Builds
<!-- Directory.Build.props -->
<PropertyGroup>
<!-- Enabled by default in .NET SDK projects since SDK 2.0+ -->
<Deterministic>true</Deterministic>
<!-- For full reproducibility, also set: -->
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>
What Deterministic Affects
- Removes timestamps from PE headers
- Uses consistent file paths in PDBs
- Produces identical output fo
Read more
name: build-perf-baseline description: "Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before/after measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output, and dependency graph trimming. Start here before diving into build-perf-diagnostics, incremental-build, or build-parallelism. DO NOT USE FOR: non-MSBuild build systems, detailed bottleneck analysis (use build-perf-diagnostics after baselining)." license: MIT
Build Performance Baseline & Optimization
Overview
Before optimizing a build, you need a **baseline**. Without measurements, optimization is guesswork. This skill covers how to establish baselines and apply systematic optimization techniques.
**Related skills:**
- `build-perf-diagnostics` — binlog-based bottleneck identification
- `incremental-build` — Inputs/Outputs and up-to-date checks
- `build-parallelism` — parallel and graph build tuning
- `eval-performance` — glob and import chain optimization
---
Step 1: Establish a Performance Baseline
Measure three scenarios to understand where time is spent:
Cold Build (First Build)
No previous build output exists. Measures the full end-to-end time including restore, compilation, and all targets.
# Clean everything first
dotnet clean
# Remove bin/obj to truly start fresh
Get-ChildItem -Recurse -Directory -Include bin,obj | Remove-Item -Recurse -Force
# OR on Linux/macOS:
# find . -type d \( -name bin -o -name obj \) -exec rm -rf {} +
# Measure cold build
dotnet build /bl:cold-build.binlog -mWarm Build (Incremental Build)
Build output exists, some files have changed. Measures how well incremental build works.
# Build once to populate outputs dotnet build -m # Make a small change (touch one .cs file) # Then rebuild dotnet build /bl:warm-build.binlog -m
No-Op Build (Nothing Changed)
Build output exists, nothing has changed. This should be nearly instant. If it's slow, incremental build is broken.
# Build once to populate outputs dotnet build -m # Rebuild immediately without changes dotnet build /bl:noop-build.binlog -m
What Good Looks Like
| Scenario | Expected Behavior | |----------|------------------| | Cold build | Full compilation, all targets run. This is your absolute baseline | | Warm build | Only changed projects recompile. Time proportional to change scope | | No-op build | < 5 seconds for small repos, < 30 seconds for large repos. All compilation targets should report "Skipping target — all outputs up-to-date" |
**Red flags:**
- No-op build > 30 seconds → incremental build is broken (see `incremental-build` skill)
- Warm build recompiles everything → project dependency chain forces full rebuild
- Cold build has long restore → NuGet cache issues
Recording Baselines
Record baselines in a structured way before and after optimization:
| Scenario | Before | After | Improvement | |-------------|---------|---------|-------------| | Cold build | 2m 15s | | | | Warm build | 1m 40s | | | | No-op build | 45s | | |
---
Step 2: MSBuild Server (Persistent Build Process)
The MSBuild server keeps the build process alive between invocations, avoiding JIT compilation and assembly loading overhead on every build.
Enabling MSBuild Server
# Enabled by default in .NET 8+ but can be forced dotnet build /p:UseSharedCompilation=true
The MSBuild server is started automatically and reused across builds. The compiler server (VBCSCompiler / `dotnet build-server`) is separate but complementary.
Managing the Build Server
# Check if the server is running dotnet build-server status # Shut down all build servers (useful when debugging) dotnet build-server shutdown
When to Restart the Build Server
Restart after:
- Updating the .NET SDK
- Changing MSBuild tooling (custom tasks, props, targets)
- Debugging build infrastructure issues
- Seeing stale behavior in repeated builds
dotnet build-server shutdown dotnet build
---
Step 3: Artifacts Output Layout
The `UseArtifactsOutput` feature (introduced in .NET 8) changes the output directory structure to avoid bin/obj clash issues and enable better caching.
Enabling Artifacts Output
<!-- Directory.Build.props --> <PropertyGroup> <UseArtifactsOutput>true</UseArtifactsOutput> </PropertyGroup>
Before vs After
# Traditional layout (before)
src/
MyLib/
bin/Debug/net8.0/MyLib.dll
obj/Debug/net8.0/...
MyApp/
bin/Debug/net8.0/MyApp.dll
# Artifacts layout (after)
artifacts/
bin/MyLib/debug/MyLib.dll
bin/MyApp/debug/MyApp.dll
obj/MyLib/debug/...
obj/MyApp/debug/...Benefits
- **No bin/obj clash**: Each project+configuration gets a unique path automatically
- **Easier to cache**: Single `artifacts/` directory to cache/restore in CI
- **Cleaner .gitignore**: Just ignore `artifacts/`
- **Multi-targeting safe**: Each TFM gets its own subdirectory
Customizing
<!-- Change the artifacts root --> <PropertyGroup> <ArtifactsPath>$(MSBuildThisFileDirectory)output</ArtifactsPath> </PropertyGroup>
---
Step 4: Deterministic Builds
Deterministic builds produce byte-for-byte identical output given the same inputs. This is essential for build caching and reproducibility.
Enabling Deterministic Builds
<!-- Directory.Build.props --> <PropertyGroup> <!-- Enabled by default in .NET SDK projects since SDK 2.0+ --> <Deterministic>true</Deterministic> <!-- For full reproducibility, also set: --> <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild> </PropertyGroup>
What Deterministic Affects
- Removes timestamps from PE headers
- Uses consistent file paths in PDBs
- Produces identical output fo
This repository contains the .NET team's curated set of core skills and custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io. 📊 Dashboard - Accuracy and efficiency scoring trends for contained plugins (
Repo: dotnet/skills
Other skills on dotnet-skills.
- /csharp-scripts
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file C# apps, small multi-file C# apps composed with `#:include`/`#:exclude`, or C# file-based apps linked with `#:ref`. Do
Open skill - /dotnet-pinvoke
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime, SafeHandle, and cross-platform patterns. USE FOR: writing new P/Invoke or LibraryImport declarations, reviewing or debugging
Open skill - /nuget-trusted-publishing
Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet OIDC, keyless NuGet publish, migrate from NuGet API key, NuGet/login, secure NuGet publishing. DO NOT USE FOR: publishing to
Open skill - /technology-selection
Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent Framework (MAF), GitHub Copilot SDK, ONNX Runtime, and OllamaSharp. Covers the full spectrum from classic ML through modern
Open skill - /configuring-opentelemetry-dotnet
Configure OpenTelemetry distributed tracing, metrics, and logging in ASP.NET Core using the .NET OpenTelemetry SDK. Use when adding observability, setting up OTLP exporters, creating custom metrics/spans, or troubleshooting distributed trace correlation.
Open skill - /convert-blazor-server-to-webapp
Guides conversion of a pre-.NET 8 Blazor Server app into a .NET 8+ Blazor Web App. USE FOR: migrating apps that use AddServerSideBlazor and MapBlazorHub to the AddRazorComponents/MapRazorComponents model, converting _Host.cshtml to an App.razor root component, replacing
Open skill

