--- name: item-management description: "Patterns for managing MSBuild item groups: Include/Remove/Update semantics, item metadata, batching with %(Metadata), transforms, per-item filtering, and cross-product batching pitfalls. USE FOR: diagnosing and fixing item group anti-patterns in .csproj files, reviewing item management for correctness, fixing CS2002 duplicate file warnings from SDK globbing, fixing targets that run more times than expected due to cross-product batching, fixing Include vs Update misuse on SDK-globbed items, fixing FileWrites registration for generated file clean support, moving generated files to IntermediateOutputPath. DO NOT USE FOR: target chain architecture (use target-authoring), property patterns (use property-patterns), incrementality (use incremental-build), general anti-patterns (use msbuild-antipatterns), non-MSBuild build systems." license: MIT --- # MSBuild Item Management Patterns Canonical patterns for working with item groups, from `Microsoft.Common.CurrentVersion.targets`. ## Include / Remove / Update — Three Operations | Operation | Purpose | When to use | |---|---|---| | `Include` | Add new items to the group | Creating items with identity + metadata | | `Remove` | Remove items matching a pattern | Excluding files or clearing a group | | `Update` | Modify metadata on existing items | Adding/changing metadata without re-adding | ### Include — Add Items ```xml true ``` ### Remove — Subtract Items ```xml <_CleanOrphanFileWrites Include="@(_CleanPriorFileWrites)" Exclude="@(_CleanCurrentFileWrites)" /> <_Temporary Remove="@(_Temporary)" /> ``` ### Update — Modify Existing Items ```xml true Microsoft.CodeAnalysis.Collections.SR ``` `Update` does not add items — it only modifies items already in the group. ## Item Batching — %(Metadata) When `%(Metadata)` appears in target attributes or task parameters, MSBuild **batches** execution per unique metadata value. ### Target-level batching (Outputs) ```xml ``` ### Task-level batching ```xml ``` ### Per-item filtering with Condition ```xml <_ResxOutput Include="@(EmbeddedResource->'%(OutputResource)')" Condition="'%(EmbeddedResource.WithCulture)' == 'false'" /> ``` ### Batching rules - `%(Metadata)` in `Condition` or `Outputs` → target batches per unique value. - `%(Metadata)` in task parameters → task batches per unique value. - **Do not mix `%()` from different item groups** in the same expression — this causes a cross-product (see Common Pitfalls). ## Item Transforms — @(Item->'expression') Transforms create new item lists by applying an expression to each item: ```xml ``` ## Exclude Pattern — Set Subtraction on Include ```xml ``` `Exclude` only works on `Include` — it cannot be used with `Update` or `Remove`. ## Conditional Item Inclusion ```xml ``` ## PrivateAssets on Tool/Analyzer Packages ```xml ``` ## Common Pitfalls ### Cross-product batching Referencing `%(Metadata)` from two different item groups creates O(N×M) executions: ```xml ``` ### Generated files in source tree Write to `$(IntermediateOutputPath)` (obj/), not the source directory. Source-tree generation pollutes version control and can cause duplicate compilation via globs. ### Missing FileWrites Every file created during a target must be added to `@(FileWrites)` for `dotnet clean` support.