
Custom Target Authoring
FreeStreamline your MSBuild target authoring process.
Free · Opens the source repo
What Custom Target Authoring does
The Custom Target Authoring skill provides a comprehensive guide to writing effective MSBuild targets using canonical patterns derived from Microsoft's own Microsoft.Common.CurrentVersion.targets. It is designed for developers who need to diagnose and fix common issues related to custom target authoring, such as broken SDK target chains, improper use of CompileDependsOn, and mismanagement of inputs and outputs. By following the provided patterns and rules, users can ensure that their builds are efficient and maintainable.
This skill emphasizes the importance of proper target chaining and extensibility. It covers the three-level target chain model, which includes Before, Core, and After targets, allowing developers to structure their builds systematically. The skill also explains the critical difference between Returns and Outputs, ensuring that users understand how to communicate between projects effectively without introducing stale data.
Furthermore, the skill highlights common pitfalls that can lead to build failures, such as overwriting DependsOn properties or misusing query targets. By adhering to the best practices outlined in this skill, developers can avoid these issues and create robust build scripts that leverage MSBuild's capabilities.
Overall, this skill is ideal for developers working with MSBuild who want to improve their target authoring practices and ensure that their build processes are both efficient and reliable.
When to use it
Use this skill when developing or maintaining MSBuild targets to ensure best practices and avoid common errors.
When not to use it
This skill is not suitable for tuning incremental builds or optimizing parallel builds; those require different approaches.
What you can build with it
Diagnosing Build Issues
When encountering build failures, use this skill to identify and fix custom target authoring mistakes.
Creating Custom Targets
Leverage the provided patterns to create new MSBuild targets that integrate seamlessly with existing build processes.
Improving Build Efficiency
Apply the best practices outlined in this skill to enhance the efficiency and reliability of your build scripts.
How to install Custom Target Authoring
View source1. Install with the skills CLI
npx skills add dotnet/skills/target-authoring --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by dotnetCustom Target Authoring Patterns
Canonical patterns from Microsoft.Common.CurrentVersion.targets in the MSBuild repository.
The Three-Level Target Chain
Every major entry point (Build, Rebuild, Clean) delegates to a property listing its dependencies, which chains through Before → Core → After:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
<Target Name="Build"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="$(BuildDependsOn)"
Returns="@(TargetPathWithTargetPlatformMoniker)" />
<!-- Empty extensibility targets — users override these -->
<Target Name="BeforeBuild" />
<Target Name="AfterBuild" />
CoreBuild delegates to $(CoreBuildDependsOn) and includes error handlers:
<Target Name="CoreBuild" DependsOnTargets="$(CoreBuildDependsOn)">
<OnError ExecuteTargets="_TimeStampAfterCompile;PostBuildEvent"
Condition="'$(RunPostBuildEvent)' == 'Always'" />
<OnError ExecuteTargets="_CleanRecordFileWrites" />
</Target>
Rules
- Delegate to a property (
DependsOnTargets="$(MyTargetDependsOn)"), not hardcoded targets. OnErrorgoes inside the orchestrating target to ensure cleanup runs even on failure.- Empty Before/After targets are extensibility points. Users override them; SDKs never put logic in them.
Chain Extension — Append, Never Overwrite
When adding a custom target to an existing chain, append to the DependsOn property:
<!-- GOOD: Append to existing chain -->
<PropertyGroup>
<CompileDependsOn>$(CompileDependsOn);MyCodeGenTarget</CompileDependsOn>
</PropertyGroup>
<!-- BAD: Overwrites the entire chain, dropping SDK targets -->
<PropertyGroup>
<CompileDependsOn>MyCodeGenTarget</CompileDependsOn>
</PropertyGroup>
DependsOnTargets vs BeforeTargets vs AfterTargets
| Mechanism | Defined in | Best for |
|---|---|---|
DependsOnTargets | The target that needs deps | Target explicitly requires others |
BeforeTargets | The injecting target | Insert before a target you don't own |
AfterTargets | The injecting target | Insert after a target you don't own |
Validation targets use BeforeTargets to intercept all entry points:
<Target Name="_CheckForInvalidConfigurationAndPlatform"
BeforeTargets="$(BuildDependsOn);Build;$(RebuildDependsOn);Rebuild;$(CleanDependsOn);Clean">
</Target>
Rules:
- Use
DependsOnTargetswhen your target needs specific prerequisites. - Use
BeforeTargets/AfterTargetswhen injecting into a pipeline you don't own. - Prefer
BeforeTargets="CoreCompile"over modifying$(CompileDependsOn)when you don't control the targets file.
Returns vs Outputs
<!-- Build returns items for consumption by referencing projects -->
<Target Name="Build"
DependsOnTargets="$(BuildDependsOn)"
Returns="@(TargetPathWithTargetPlatformMoniker)" />
<!-- GetTargetPath is a lightweight query target -->
<Target Name="GetTargetPath" Returns="@(TargetPathWithTargetPlatformMoniker)" />
Returnsspecifies what the MSBuild task receives when calling this project. Use for inter-project communication.Outputson inner targets is for incrementality (timestamp checks). Use for up-to-date detection.- Never mix the two purposes. Query targets (
GetTargetPath,GetTargetFrameworks) should useReturns, notOutputs.
Target Naming Conventions
| Pattern | Meaning | Example |
|---|---|---|
_PrefixedName | Internal/private target | _TimeStampBeforeCompile |
CoreXxx | The actual implementation | CoreBuild, CoreCompile |
BeforeXxx / AfterXxx | Empty extensibility hooks | BeforeBuild, AfterCompile |
PrepareXxx | Setup/validation phase | PrepareForBuild |
ResolveXxx | Discovery/resolution phase | ResolveReferences |
GetXxx | Lightweight query (no side effects) | GetTargetPath |
Complete Custom Target Template
<!-- 1. Define the DependsOn chain for extensibility -->
<PropertyGroup>
<MyFeatureDependsOn>
_ValidateMyFeatureInputs;
BeforeMyFeature;
CoreMyFeature;
AfterMyFeature
</MyFeatureDependsOn>
</PropertyGroup>
<!-- 2. Outer target with Returns for inter-project communication -->
<Target Name="MyFeature"
DependsOnTargets="$(MyFeatureDependsOn)"
Returns="@(MyFeatureOutput)" />
<!-- 3. Empty extensibility points -->
<Target Name="BeforeMyFeature" />
<Target Name="AfterMyFeature" />
<!-- 4. Core implementation with Inputs/Outputs for incrementality -->
<Target Name="CoreMyFeature"
Inputs="$(MSBuildAllProjects);@(MyFeatureInput)"
Outputs="$(IntermediateOutputPath)myfeature.generated.cs">
<Exec Command="my-tool.exe -o $(IntermediateOutputPath)myfeature.generated.cs" />
<!-- 5. Register outputs for clean tracking -->
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)myfeature.generated.cs" />
<FileWrites Include="$(IntermediateOutputPath)myfeature.generated.cs" />
</ItemGroup>
</Target>
<!-- 6. Validation target runs first in the dependency chain -->
<Target Name="_ValidateMyFeatureInputs">
<Error Text="MyFeatureInput items are required."
Condition="'@(MyFeatureInput)' == ''" />
</Target>
Common Pitfalls
- Overwriting
DependsOnproperties drops SDK targets silently. Always include$(ExistingProperty)when appending. - Using
Outputson query targets causes MSBuild to skip them when "up to date," returning stale data. UseReturns. - Defining targets in
.propsmeansBeforeTargetson SDK targets have nothing to hook into yet. Move targets to.targets. - Forgetting
OnErrorin orchestrating targets means file tracking fails on build errors, breaking subsequent incremental builds.
Frequently asked questions about Custom Target Authoring
Similar skills
Rhino 3D Scripting
Streamline your Rhinoceros 3D scripting tasks.
MVVM Toolkit
Streamline ViewModel development with source generators.
FreeCAD Scripts
Generate Python scripts for FreeCAD automation and modeling.
Azure Architecture Builder
Design and deploy Azure infrastructure using natural language.
Command Development
Streamline your command creation for Claude Code.
Create Cowork Plugin
Easily build and package plugins through guided sessions.
