---
title: "pnpm install Slow in GitHub Actions | StarSling"
description: "pnpm install taking minutes in CI usually means the store isn't cached, setup order is wrong, or the same install runs more than once per workflow."
url: https://starsling.dev/github-actions/problems/slow-pnpm-install
canonicalUrl: https://starsling.dev/github-actions/problems/slow-pnpm-install
---

# pnpm install is slow in GitHub Actions

[GitHub Actions](https://starsling.dev/github-actions) / [Problems](https://starsling.dev/github-actions/problems) / pnpm install is slow in GitHub Actions

- [How StarSling works](https://starsling.dev/)

Diagnosis mode: static. Last updated: 2026-08-31

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.

## Table of contents

- [Symptoms](#symptoms)
- [How to diagnose it](#how-to-diagnose-it)
- [Likely causes](#likely-causes)
- [Hand it to an agent](#verify)
- [Related pages](#related-pages)
- [Related symptoms](#related-symptoms)
- [Sources](#sources)

<a id="symptoms"></a>

## 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.

<a id="how-to-diagnose-it"></a>

## How to diagnose it

[ci-speedup](https://starsling.dev/ci-speedup) carries the detection logic behind the causes below and opens the fix as a reviewable pull request. Install it with `npx skills add starslingdev/skills`, then run `/ci-speedup` in your repository.

To check by hand:

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.

<a id="likely-causes"></a>

## 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](https://starsling.dev/github-actions/optimizations/optimize-pnpm-install) (`ci.cache.pnpm-store`, detection mode static)

### 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](https://starsling.dev/best-practices/github-actions/cache-dependencies) (`ci.cache.dependency-cache`, detection mode static)

### 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](https://starsling.dev/github-actions/optimizations/avoid-duplicate-dependency-installs) (`ci.cache.duplicate-installs`, detection mode static)

### 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](https://starsling.dev/github-actions/optimizations/avoid-duplicated-setup) (`ci.hygiene.duplicated-setup`, detection mode static)

<a id="verify"></a>

## 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:

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.

<a id="related-pages"></a>

## Related pages

- [Optimize pnpm installs in GitHub Actions](https://starsling.dev/github-actions/optimizations/optimize-pnpm-install)
- [GitHub Actions cache: dependencies, keys, and cache hits](https://starsling.dev/best-practices/github-actions/cache-dependencies)
- [Stop reinstalling the same dependencies in GitHub Actions](https://starsling.dev/github-actions/optimizations/avoid-duplicate-dependency-installs)
- [Share setup steps across GitHub Actions jobs](https://starsling.dev/github-actions/optimizations/avoid-duplicated-setup)
- [Why is my GitHub Actions CI so slow?](https://starsling.dev/github-actions-too-slow)

<a id="related-symptoms"></a>

## Related symptoms

Other symptoms on this site that share a likely cause with this one. If none of the causes above is yours, one of these is usually the page you wanted.

- [npm install or npm ci taking a large slice of every run](https://starsling.dev/github-actions/problems/slow-npm-install)
- [Why your test job is slower in CI than it is locally](https://starsling.dev/github-actions/problems/slow-tests)
- [Why is the Playwright job so slow in CI](https://starsling.dev/github-actions/problems/slow-playwright)

<a id="sources"></a>

## Sources

- [pnpm: Continuous Integration](https://pnpm.io/continuous-integration)
- [actions/setup-node: caching global packages data](https://github.com/actions/setup-node#caching-global-packages-data)
- [pnpm/action-setup](https://github.com/pnpm/action-setup)
