Skip to content
Latchkey

dotnet restore not cached, re-downloading every run in CI

When the NuGet global packages folder is not cached between runs, every CI job re-downloads all dependencies. That is slow and re-exposes the job to any transient feed error on each run.

What this error means

restore takes minutes on every run and occasionally fails on a transient feed timeout, because nothing is cached and each job fetches every package from scratch.

dotnet
Determining projects to restore...
  Restored /home/runner/work/app/app.csproj (in 3 min 42 sec).

Common causes

No cache of the global packages folder

Without caching ~/.nuget/packages, restore downloads every dependency again on each run.

Cache key does not track the lockfile

A cache keyed on something other than the lockfile either never hits or serves a stale set, so restore falls back to downloading.

How to fix it

Cache the NuGet packages folder

  1. Cache ~/.nuget/packages keyed on the lockfiles.
  2. Restore against the cache so unchanged dependencies are not re-fetched.
  3. Invalidate only when a lockfile changes.
.github/workflows/ci.yml
- uses: actions/cache@v4
  with:
    path: ~/.nuget/packages
    key: nuget-${{ hashFiles('**/packages.lock.json') }}

Enable the built-in cache with lockfiles

setup-dotnet can cache automatically when a lockfile is present, keeping restore fast and deterministic.

.github/workflows/ci.yml
- uses: actions/setup-dotnet@v4
  with:
    dotnet-version: '8.0.x'
    cache: true

How to prevent it

  • Cache ~/.nuget/packages keyed on the lockfiles.
  • Commit lockfiles so cache keys are stable and deterministic.
  • Invalidate the cache only when dependencies actually change.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →