pnpm install is slow in GitHub Actions

A slow pnpm install in GitHub Actions almost always means the pnpm store is not being cached or restored, not that pnpm itself is slow. Check cache configuration and setup order first, then look for the same install running more than once across jobs.

static · checkable from the repo
How StarSling works

AI agents find the cause

StarSling agents run this diagnosis against your workflows and run history, identify which cause is yours, and open the fix as a reviewable PR.

Symptoms

pnpm's speed claim rests on a content-addressable store that it can restore from a cache instead of downloading every package fresh, and every one of the causes below is a different way that restore fails to happen. The most common failure is caching node_modules or nothing at all instead of the pnpm store path, since the store and node_modules are different directories with different content and only the store is cache-worthy across installs. The next most common is running pnpm/action-setup after actions/setup-node, which breaks the cache key computation setup-node needs before pnpm exists on the runner. After caching is confirmed correct, check whether the workflow installs dependencies more than once, either in the same job through a stray duplicate step or across multiple jobs that each run a full install instead of sharing one. These four causes are ordered by how often a slow install traces back to them: store caching first, then general dependency caching gaps, then duplicate installs within a workflow, then duplicated setup across jobs.

  • The install step in the Actions log takes several minutes even though the same pnpm install finishes in seconds on your machine.

  • The cache step in the workflow log reports a cache miss on every run, or there is no cache step for pnpm at all.

  • Multiple jobs in the same workflow each run their own pnpm install, and the total install time scales with the number of jobs.

  • You see pnpm install invoked more than once inside a single job's step list.

  • Switching runners or bumping the pnpm version made an install that used to be fast slow again.

How to diagnose it

  1. Open the failing run in the GitHub Actions UI and expand the pnpm install step; note its wall-clock duration and whether a preceding cache step reports cache-hit: true or false.

  2. Run grep -rn 'pnpm/action-setup\|actions/setup-node' .github/workflows/<file>.yml and read the two matches in order; pnpm/action-setup must come first.

  3. Run grep -n "cache:" .github/workflows/<file>.yml to confirm cache: 'pnpm' is set on the setup-node step in the same job as the slow install.

  4. Run grep -c 'pnpm install' .github/workflows/<file>.yml to count total install invocations in the file, then check whether that count exceeds one per job.

  5. If the cache step shows a hit but the install is still slow, check for pnpm version drift: jq -r '.packageManager // "unset"' package.json prints the version the repo pins, and grep -rn -A2 'pnpm/action-setup' .github/workflows/ prints the version each workflow installs. There is no pattern field in package.json; the pinned version lives in packageManager. If it prints unset, or a workflow pins a different major, jobs can build incompatible stores and miss each other's cache.

  6. Confirm the store path itself: run pnpm store path locally and check that the cached path in the workflow's actions/cache step (or the implicit path used by cache: 'pnpm') matches it, not a node_modules path.

Likely causes

Ordered by how often each one turns out to be the answer. Confirm a cause with its check before you change anything.

  1. The pnpm store path isn't cached, or setup order breaks the cache

    pnpm keeps a content-addressable store, separate from node_modules, that it can reuse across installs instead of re-downloading packages. If the workflow caches node_modules or nothing at all, that store never persists between runs, so every install refetches everything from the registry. This also fails silently when pnpm/action-setup runs after actions/setup-node, because setup-node needs pnpm already on the PATH to compute the store's cache key, so cache: 'pnpm' in setup-node has nothing to key against.

    Confirm it

    Run grep -rn 'actions/setup-node\|pnpm/action-setup' .github/workflows/ and confirm pnpm/action-setup appears before actions/setup-node in the step order, and that setup-node has cache: 'pnpm' set.

    Fix: pnpm store caching
  2. No dependency cache action is configured at all

    Some workflows install dependencies with no caching action present anywhere in the job, which means every run pays the full download and extraction cost with nothing to restore. This is distinct from the pnpm-store-specific misconfiguration above: here there may be no actions/cache or setup-node cache step for any ecosystem in the job, and in a matrix or sharded workflow the missing cache cost multiplies by every parallel job.

    Confirm it

    Run grep -rn 'actions/cache\|cache:' .github/workflows/ across the workflow that runs the slow install and confirm a cache step actually exists for the job in question, not just for a different job in the same file.

    Fix: Dependency caching
  3. The same install runs more than once in the workflow

    A workflow can have correct caching and still be slow if pnpm install executes twice: once as a dedicated setup step and again inside a later step, often left over from a workaround for stale artifacts. Each additional invocation pays store-lookup and dependency-resolution time again even when nothing changed, and the second run is pure waste with no fix beyond removing it.

    Confirm it

    Run grep -oP '(?<=run: ).*install.*' .github/workflows/<file>.yml | sort | uniq -d on the workflow to list any install command that appears more than once within the same job.

    Fix: Duplicate dependency installs
  4. Every job repeats checkout and install instead of sharing setup

    When several jobs in one workflow each run their own checkout, pnpm/action-setup, and install sequence, the total install time scales with job count even if every individual cache hits cleanly, because the store restore, lockfile verification, and symlink construction under node_modules still happen once per job. This is the setup being duplicated across jobs, as opposed to duplicated within a single job's steps.

    Confirm it

    Run grep -c 'pnpm install' .github/workflows/<file>.yml and compare it against the number of jobs defined in the file; if the count matches or exceeds the job count, look at whether any of those jobs could consume artifacts from a build job instead of installing independently.

    Fix: Duplicated job setup

Hand it to an agent

Hand this prompt to your coding agent (Claude Code, Cursor, and the like) to run this diagnosis against your repository and report which cause it found.

Prompt for your coding agent
Diagnose why `pnpm install` is slow in this repository's GitHub Actions workflows. Do not change anything yet. First, run `grep -rn 'pnpm/action-setup\|actions/setup-node' .github/workflows/` and check whether pnpm/action-setup runs before actions/setup-node, and whether setup-node has `cache: 'pnpm'` set, in that order (ci.cache.pnpm-store). Second, run `grep -rn 'actions/cache\|cache:' .github/workflows/` and confirm a cache step exists at all for the job that runs the slow install (ci.cache.dependency-cache). Third, in the specific workflow file with the slow install, run `grep -oP '(?<=run: ).*install.*' <file> | sort | uniq -d` to find any install command repeated within one job (ci.cache.duplicate-installs). Fourth, count `pnpm install` occurrences against job count in that file to check for duplicated setup across jobs (ci.hygiene.duplicated-setup). Report which of these four causes you found evidence for, in the order checked, with the exact grep output backing each conclusion, before proposing any fix.

Go further

Find the cause, fix them all, or keep them fixed.

You have the prompt that works out which cause applies. Here is how much further you can take it, each step doing more for you than the last.

  1. Find the cause

    Copy the diagnosis prompt above

    Hand it to your coding agent to confirm which cause applies in your repo. It reports back what it found and changes nothing.

  2. Fix them all, once

    Install the ci-speedup skill

    One prompt audits your whole repo against all 73 ci-speedup patterns (these 10 plus 63 more) and hands your agent every fix at once. Open source, MIT, runs locally.

  3. Keep it fixed, forever

    Install the StarSling GitHub App

    Connect GitHub and the fixes stay applied as your CI evolves, with agents that keep inspecting your workflows and opening optimization PRs you review.

Sources

1pnpm: Continuous Integration (opens in new tab)

2actions/setup-node: caching global packages data (opens in new tab)

3pnpm/action-setup (opens in new tab)

Last updated 2026-08-31