/copy-to-output-directory
Choosing an MSBuild CopyToOutputDirectory / CopyToPublishDirectory mode: Never, PreserveNewest, Always, and IfDifferent (MSBuild 17.13+), plus $(SkipUnchangedFilesOnCopyAlways). USE FOR: removing the per-build Always copy perf hit; resetting output files mutated between builds.
$ npx -y skills add managedcode/dotnet-skills --skill copy-to-output-directory --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
/copy-to-output-directory
Context preview
The summary Claude sees to decide when to auto-load this skill.
Choosing an MSBuild CopyToOutputDirectory / CopyToPublishDirectory mode: Never, PreserveNewest, Always, and IfDifferent (MSBuild 17.13+), plus $(SkipUnchangedFilesOnCopyAlways). USE FOR: removing the per-build Always copy perf hit; resetting output files mutated between builds.
SKILL.md
copy-to-output-directory.SKILL.mdname: copy-to-output-directory
description: "Choosing an MSBuild CopyToOutputDirectory / CopyToPublishDirectory mode: Never, PreserveNewest, Always, and IfDifferent (MSBuild 17.13+), plus $(SkipUnchangedFilesOnCopyAlways). USE FOR: removing the per-build Always copy perf hit; resetting output files mutated between builds. DO NOT USE FOR: general incremental-build diagnosis (use incremental-build); non-MSBuild build systems."
license: MIT
Choosing a CopyToOutputDirectory Mode
Overview
The `CopyToOutputDirectory` metadata (and its publish counterpart `CopyToPublishDirectory`) controls whether an item — `Content`, `None`, `EmbeddedResource`, or `Compile` — is copied next to your build output, and under what conditions the copy happens. Picking the wrong mode causes either stale files in `bin/` or an unnecessary per-build performance hit.
As of **MSBuild 17.13 / .NET SDK 9.0.2xx** there are four values:
| Mode | Copies when… | Incremental cost | Typical use | | --- | --- | --- | --- | | `Never` (default) | Never | None | Files not needed at runtime | | `PreserveNewest` | Source is **newer** than destination (or destination missing) | Cheap (timestamp check) | The common case — source files you edit | | `Always` | **Every build**, unconditionally | Expensive — copies on every build even in no-op builds | Legacy workaround; avoid (see below) | | `IfDifferent` | Source **differs** from destination in either direction (newer **or** older, or size differs, or destination missing) | Cheap (timestamp + size check) | Destination may be mutated between builds |
<ItemGroup>
<None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
<None Include="testdata\seed.db" CopyToOutputDirectory="IfDifferent" />
</ItemGroup>
You can use either the attribute form shown above or the child-element form:
<None Include="testdata\seed.db">
<CopyToOutputDirectory>IfDifferent</CopyToOutputDirectory>
</None>
Why `Always` is usually the wrong choice
`Always` re-copies the file on **every** build, including otherwise-clean incremental/no-op builds. On projects with many or large content files this is a measurable, recurring cost and a common cause of "why is my no-op build not instant?" reports.
Historically `Always` was the only way to handle a specific scenario: **the destination file can change between builds** — for example an SQLite database, a storage/state file, or a config file that a test run mutates. With `PreserveNewest`, if the destination is modified (making its timestamp *newer* than the source) MSBuild will *not* restore the original source file, because the source is no longer newer. People reached for `Always` to force the file back into a known-good state — paying the copy cost on every build as a side effect.
`IfDifferent`: copy when different, in either direction
`IfDifferent` is the targeted fix for that scenario. It copies the source over the destination whenever MSBuild considers the two **different** — whether the source is newer *or* older than the destination, whether the size differs, or the destination is missing — and skips the copy when the destination is unchanged per MSBuild's heuristic.
Under the hood the `_CopyDifferingSourceItemsToOutputDirectory` target uses the `Copy` task with `SkipUnchangedFiles="true"`. That "unchanged" check is a **heuristic**: it compares **last-write timestamp and file size only** — not a content hash — so a destination that was edited to the same size and timestamp as the source is treated as unchanged and is *not* re-copied. In practice this restores a mutated destination back to the source version on the next build (the reason people reached for `Always`) while avoiding the unconditional per-build copy.
Use `IfDifferent` when:
- A test run or the app itself writes to the copied file (databases, caches, state/storage files, editable config) and you want each build to reset it to the source version.
- You were using `Always` purely as a "keep the output in sync with the source" mechanism, not because you truly need a copy on every single build.
<ItemGroup>
<!-- Reset the fixture DB to the source copy whenever it has drifted,
but don't pay a copy on every no-op build. -->
<None Include="fixtures\catalog.db" CopyToOutputDirectory="IfDifferent" />
</ItemGroup>Globally softening `Always` with `$(SkipUnchangedFilesOnCopyAlways)`
If you have an existing codebase full of `CopyToOutputDirectory="Always"` items and want the performance benefit without editing every item, set the property:
<PropertyGroup>
<SkipUnchangedFilesOnCopyAlways>true</SkipUnchangedFilesOnCopyAlways>
</PropertyGroup>
This makes the `_CopyOutOfDateSourceItemsToOutputDirectoryAlways` target pass `SkipUnchangedFiles="true"` to its `Copy` task, so `Always` items are only copied when they actually differ — effectively giving `Always` the same skip-unchanged behavior as `IfDifferent`.
- Default is `false` for backwards compatibility (classic `Always` = copy every build).
- Set it in `Directory.Build.props` to opt an entire repo in at once.
- Prefer converting individual items to `IfDifferent` when you can; use this property when a bulk, non-invasive opt-in is more practical.
How the modes flow through the build
`GetCopyToOutputDirectoryItems` buckets each item by its `CopyToOutputDirectory` value. Three copy targets then do the work as dependencies of `_CopySourceItemsToOutputDirectory` (which is itself invoked by `CopyFilesToOutputDirectory`):
- `_CopyOutOfDateSourceItemsToOutputDirectory` — `PreserveNewest` items (incremental via `Inputs`/`Outputs` timestamp comparison).
- `_CopyOutOfDateSourceItemsToOutputDirectoryAlways` — `Always` items (unconditional copy unless `$(SkipUnchangedFilesOnCopyAlways)` is `true`).
- `_CopyDifferingSourceItemsToOutputDirectory` — `IfDifferent` items (`SkipUnchangedFiles="true"`).
All copied files are registered in `FileWrites`, so `dotnet cl
Read more
name: copy-to-output-directory description: "Choosing an MSBuild CopyToOutputDirectory / CopyToPublishDirectory mode: Never, PreserveNewest, Always, and IfDifferent (MSBuild 17.13+), plus $(SkipUnchangedFilesOnCopyAlways). USE FOR: removing the per-build Always copy perf hit; resetting output files mutated between builds. DO NOT USE FOR: general incremental-build diagnosis (use incremental-build); non-MSBuild build systems." license: MIT
Choosing a CopyToOutputDirectory Mode
Overview
The `CopyToOutputDirectory` metadata (and its publish counterpart `CopyToPublishDirectory`) controls whether an item — `Content`, `None`, `EmbeddedResource`, or `Compile` — is copied next to your build output, and under what conditions the copy happens. Picking the wrong mode causes either stale files in `bin/` or an unnecessary per-build performance hit.
As of **MSBuild 17.13 / .NET SDK 9.0.2xx** there are four values:
| Mode | Copies when… | Incremental cost | Typical use | | --- | --- | --- | --- | | `Never` (default) | Never | None | Files not needed at runtime | | `PreserveNewest` | Source is **newer** than destination (or destination missing) | Cheap (timestamp check) | The common case — source files you edit | | `Always` | **Every build**, unconditionally | Expensive — copies on every build even in no-op builds | Legacy workaround; avoid (see below) | | `IfDifferent` | Source **differs** from destination in either direction (newer **or** older, or size differs, or destination missing) | Cheap (timestamp + size check) | Destination may be mutated between builds |
<ItemGroup> <None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" /> <None Include="testdata\seed.db" CopyToOutputDirectory="IfDifferent" /> </ItemGroup>
You can use either the attribute form shown above or the child-element form:
<None Include="testdata\seed.db"> <CopyToOutputDirectory>IfDifferent</CopyToOutputDirectory> </None>
Why `Always` is usually the wrong choice
`Always` re-copies the file on **every** build, including otherwise-clean incremental/no-op builds. On projects with many or large content files this is a measurable, recurring cost and a common cause of "why is my no-op build not instant?" reports.
Historically `Always` was the only way to handle a specific scenario: **the destination file can change between builds** — for example an SQLite database, a storage/state file, or a config file that a test run mutates. With `PreserveNewest`, if the destination is modified (making its timestamp *newer* than the source) MSBuild will *not* restore the original source file, because the source is no longer newer. People reached for `Always` to force the file back into a known-good state — paying the copy cost on every build as a side effect.
`IfDifferent`: copy when different, in either direction
`IfDifferent` is the targeted fix for that scenario. It copies the source over the destination whenever MSBuild considers the two **different** — whether the source is newer *or* older than the destination, whether the size differs, or the destination is missing — and skips the copy when the destination is unchanged per MSBuild's heuristic.
Under the hood the `_CopyDifferingSourceItemsToOutputDirectory` target uses the `Copy` task with `SkipUnchangedFiles="true"`. That "unchanged" check is a **heuristic**: it compares **last-write timestamp and file size only** — not a content hash — so a destination that was edited to the same size and timestamp as the source is treated as unchanged and is *not* re-copied. In practice this restores a mutated destination back to the source version on the next build (the reason people reached for `Always`) while avoiding the unconditional per-build copy.
Use `IfDifferent` when:
- A test run or the app itself writes to the copied file (databases, caches, state/storage files, editable config) and you want each build to reset it to the source version.
- You were using `Always` purely as a "keep the output in sync with the source" mechanism, not because you truly need a copy on every single build.
<ItemGroup>
<!-- Reset the fixture DB to the source copy whenever it has drifted,
but don't pay a copy on every no-op build. -->
<None Include="fixtures\catalog.db" CopyToOutputDirectory="IfDifferent" />
</ItemGroup>Globally softening `Always` with `$(SkipUnchangedFilesOnCopyAlways)`
If you have an existing codebase full of `CopyToOutputDirectory="Always"` items and want the performance benefit without editing every item, set the property:
<PropertyGroup> <SkipUnchangedFilesOnCopyAlways>true</SkipUnchangedFilesOnCopyAlways> </PropertyGroup>
This makes the `_CopyOutOfDateSourceItemsToOutputDirectoryAlways` target pass `SkipUnchangedFiles="true"` to its `Copy` task, so `Always` items are only copied when they actually differ — effectively giving `Always` the same skip-unchanged behavior as `IfDifferent`.
- Default is `false` for backwards compatibility (classic `Always` = copy every build).
- Set it in `Directory.Build.props` to opt an entire repo in at once.
- Prefer converting individual items to `IfDifferent` when you can; use this property when a bulk, non-invasive opt-in is more practical.
How the modes flow through the build
`GetCopyToOutputDirectoryItems` buckets each item by its `CopyToOutputDirectory` value. Three copy targets then do the work as dependencies of `_CopySourceItemsToOutputDirectory` (which is itself invoked by `CopyFilesToOutputDirectory`):
- `_CopyOutOfDateSourceItemsToOutputDirectory` — `PreserveNewest` items (incremental via `Inputs`/`Outputs` timestamp comparison).
- `_CopyOutOfDateSourceItemsToOutputDirectoryAlways` — `Always` items (unconditional copy unless `$(SkipUnchangedFilesOnCopyAlways)` is `true`).
- `_CopyDifferingSourceItemsToOutputDirectory` — `IfDifferent` items (`SkipUnchangedFiles="true"`).
All copied files are registered in `FileWrites`, so `dotnet cl
Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.
Repo: managedcode/dotnet-skills
Other skills on dotnet-skills.
- /aspnet-core
Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging, and deployment patterns on current .NET. USE FOR: working on ASP.NET Core apps, services, or middleware; changing auth, routing, configuration,
Open skill - /aspire
Build, upgrade, and operate Aspire 13.4.x C# or TypeScript application hosts with the current CLI, AppHost, ServiceDefaults, integrations, dashboard, testing, MCP, and deployment patterns for distributed apps. USE FOR: Aspire.AppHost.Sdk, Aspire.Hosting.*,
Open skill - /azure-functions
Build, review, or migrate Azure Functions in .NET with correct execution model, isolated worker setup, bindings, DI, and Durable Functions patterns. USE FOR: working on Azure Functions in .NET; migrating from the in-process model to the isolated worker model; adding Durable
Open skill - /blazor
Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices. USE FOR: building interactive web UIs with C# instead of JavaScript; choosing between Server, WebAssembly, or
Open skill - /entity-framework6
Maintain or migrate EF6-based applications with realistic guidance on what to keep, what to modernize, and when EF Core is or is not the right next step. USE FOR: EF6 codebases; runtime versus ORM migration decisions; EDMX, code-first, ObjectContext, and legacy data-access
Open skill - /entity-framework-core
Design, tune, or review EF Core data access with proper modeling, migrations, query translation, performance, and lifetime management for modern .NET applications. USE FOR: DbContext, migrations, model configuration, EF queries, tracking, loading, performance, transactions, and
Open skill

