Skip to content
Development
Skill

/eliminate-redundant-restores

Remove repeated NuGet restores from multi-step .NET builds safely. USE FOR: build/test/publish steps that each restore, Directory.Build.rsp with -restore, safe restore suppression, NETSDK1004/NETSDK1047 after --no-restore. DO NOT USE FOR: slow first restore, only one restore,

BOOST
From plugin
dotnet-skills
5.7k105 skills20 agents
Install
$ npx -y skills add dotnet/skills --skill eliminate-redundant-restores --agent claude-code

How 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/eliminate-redundant-restores

Context preview

The summary Claude sees to decide when to auto-load this skill.

Remove repeated NuGet restores from multi-step .NET builds safely. USE FOR: build/test/publish steps that each restore, Directory.Build.rsp with -restore, safe restore suppression, NETSDK1004/NETSDK1047 after --no-restore. DO NOT USE FOR: slow first restore, only one restore,

SKILL.md

eliminate-redundant-restores.SKILL.md
name: eliminate-redundant-restores
description: "Remove repeated NuGet restores from multi-step .NET builds safely. USE FOR: build/test/publish steps that each restore, Directory.Build.rsp with -restore, safe restore suppression, NETSDK1004/NETSDK1047 after --no-restore. DO NOT USE FOR: slow first restore, only one restore, version or lock errors, unranked build slowness (use build-perf-baseline)."
license: MIT

Eliminate Redundant Restores

A no-op restore still evaluates every project and checks restore state, so each extra restore in a multi-step build costs seconds to tens of seconds in a large repo. The cure is easy to get wrong: `--no-restore` on a step that no earlier restore actually covered turns a slow build into a failed one. This skill finds which invocations restore, proves which are already covered, and changes only those.

When to Use

  • A pipeline or script runs several `dotnet`/`msbuild` steps and the log shows restore output in more than one of them
  • A restore step exists, yet later steps still print `Determining projects to restore...`
  • A repository `Directory.Build.rsp` or the active MSBuild installation's `MSBuild.rsp` contains `-restore`
  • Someone asks where `--no-restore` or `-restore:false` can safely be added
  • `NETSDK1004` or `NETSDK1047` appeared after `--no-restore` was added

When Not to Use

  • The first restore is slow (feed latency, missing package cache): that is caching, not redundancy
  • There is only one restore across all invocations: nothing to deduplicate
  • Restore errors about versions, lock files or auditing: fix the restore itself
  • Unranked "why is my build slow": start with `build-perf-baseline`, then `build-perf-diagnostics`

Inputs

Discover repository inputs in the working directory; do not ask the user for paths.

  • CI definitions (`*.yml`, `.github/workflows`, `azure-pipelines*.yml`, `Jenkinsfile`) and build scripts (`build.cmd`, `build.sh`, `build.ps1`, `eng/`)
  • `Directory.Build.rsp`, `Directory.Build.props`/`.targets`, `NuGet.config`
  • Auto-loaded `MSBuild.rsp` beside the active MSBuild executable, or response files passed explicitly with `@file`. A repository-local `MSBuild.rsp` is not auto-loaded
  • Restore evidence if present: step logs or a binlog

Workflow

Step 1: Confirm restore is repeated and worth removing

  • Log evidence: `Determining projects to restore...` or `All projects are up-to-date for restore.` once per invocation.
  • Binlog evidence: restore evaluations carry the global properties `MSBuildRestoreSessionId` and `ExcludeRestorePackageImports=true`; the Target Performance Summary lists `Restore` with N calls.
  • Quantify each no-op restore. If there is one restore, or the repeated ones total about a second, report "nothing worth removing" and stop without editing.

Step 2: Inventory every invocation in execution order

| Invocation | Restores? | |---|---| | `dotnet build`, `test`, `publish`, `pack` | Implicitly, unless `--no-restore`; also check inherited rsp flags | | `dotnet run` | Implicitly before building; `--no-restore` can still inherit rsp restore on older SDKs. With `--no-build`, no build or restore runs | | `dotnet test`, `publish`, `pack` with `--no-build` | No implicit restore, but an rsp `-restore` can still enable restore; add `--no-restore -restore:false` | | `dotnet msbuild`, `msbuild.exe`, CI MSBuild tasks | With `-restore` or `-t:Restore`, including flags inherited from repository `Directory.Build.rsp` or installation-level `MSBuild.rsp`, even when a step looks build-only | | `dotnet restore`, `nuget restore`, `msbuild -t:Restore` | Explicit restore | | CI build task with a "restore packages" option | Check its default |

Starting with .NET SDK 9.0.1xx, `--no-restore` forwards `-restore:false` to override rsp flags; older SDKs can still inherit `-restore` despite skipping the CLI's implicit restore. Whenever an rsp enables restore, use the version-independent `--no-restore -restore:false` with `dotnet build`, `test`, `publish` or `pack`, even with `--no-build`. `dotnet msbuild` and `msbuild.exe` take `-restore:false`, not `--no-restore`.

`dotnet run` does not expose the MSBuild `-restore:false` override. With an rsp on older SDKs, first build using `dotnet build --no-restore -restore:false`, then run using `dotnet run --no-build` with the same project, configuration, framework and runtime inputs (or execute the built DLL directly). Passing `-restore:false` to `dotnet run` is not a restore-suppression strategy.

Step 3: Decide per invocation

Keep the first restore. Skip a later one only when all four checks pass:

| Check | If it fails | |---|---| | **Same project set.** A restore covers its entry project or solution and that project's ProjectReference closure. It does not cover a project in another solution or `.slnf`, a tool built from another path, or a project an orchestrating `.proj` builds through the `MSBuild` task (`-restore` on the orchestrator leaves those unrestored and they fail with NETSDK1004) | Keep restore on that step, or add the project to the explicit restore step | | **Same restore inputs.** `-r`/`--runtime`, RID-producing `-a`/`--arch`, `--os`, `--ucr`/`--use-current-runtime`, `TargetFramework(s)`, `RuntimeIdentifier(s)`, `PublishAot`, package sources (`--source`, `--configfile`, `RestoreSources`), `RestorePackagesPath`, and any `-p:` value a PackageReference condition reads. Architecture/OS options combine with the SDK's current RID; `--use-current-runtime` selects it. Missing RID targets fail with NETSDK1047 (`Assets file ... doesn't have a target for 'net10.0/linux-x64'`) | Match the effective RID in the explicit restore (for example `publish --os linux --arch x64` requires `restore -r linux-x64`), or keep restore on the later step. A generic restore does not cover these aliases merely because there is no `-r`. Do not require `SelfContained=true` on restore solely because publish is self-contained: RID-only restore covers ordinary SDK projects. M

Read more
Ships withdotnet-skills

This repository contains the .NET team's curated set of portable skills and host-specific custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.

Get the whole plugin

Other skills on dotnet-skills.