Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}
Comment on lines +39 to +42
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

pnpm GitHub Actions cache setup best practices node_modules

💡 Result:

Best practices (pnpm + GitHub Actions caching)

  1. Cache the pnpm store, not node_modules. actions/setup-node explicitly does not cache node_modules; it caches package-manager data (for pnpm: the store) instead. [1]
  2. Use built-in caching (actions/setup-node) whenever possible: set cache: 'pnpm' so you don’t have to hand-roll actions/cache keys/paths. [1][2]
  3. For monorepos / non-root lockfiles, set cache-dependency-path to the correct pnpm-lock.yaml location(s), otherwise the cache key may not reflect the right dependency graph. [1]
  4. Pin pnpm via packageManager (or explicit action version) to keep installs reproducible across runners/over time (e.g., pnpm/action-setup@v4 + version: 10, or rely on packageManager in package.json). [3]
  5. If you use pnpm/action-setup caching instead, enable its store caching (cache: true) and (for monorepos) point it at the right lockfile(s) via cache_dependency_path. [3]

Recommended workflow snippet (most common / simplest)

steps:
  - uses: actions/checkout@v4

  - uses: pnpm/action-setup@v4
    with:
      version: 10

  - uses: actions/setup-node@v6
    with:
      node-version: 20
      cache: pnpm
      # monorepo example:
      # cache-dependency-path: |
      #   pnpm-lock.yaml
      #   packages/*/pnpm-lock.yaml

  - run: pnpm install --frozen-lockfile
  - run: pnpm test

Sources: actions/setup-node caching behavior + cache-dependency-path + “does not cache node_modules” [1]; pnpm’s GitHub Actions example using cache: "pnpm" [2]; pnpm/action-setup cache inputs (cache, cache_dependency_path) [3].

References

[1] https://github.com/actions/setup-node
[2] https://pnpm.io/next/continuous-integration
[3] https://github.com/pnpm/action-setup


🏁 Script executed:

# Find and examine the full CI workflow file to understand the context
fd "ci.yml" --type f

Repository: npmx-dev/npmx.dev

Length of output: 43


🏁 Script executed:

# Now let's examine the actual workflow file
cat -n .github/workflows/ci.yml | head -50

Repository: npmx-dev/npmx.dev

Length of output: 1635


🏁 Script executed:

# Also check if there are pnpm/action-setup references
rg "pnpm/action-setup" .github/workflows/ci.yml -A 2 -B 2

Repository: npmx-dev/npmx.dev

Length of output: 1415


Remove the manual actions/cache step for node_modules.

The pnpm/action-setup with cache: true (line 37) already caches the pnpm store, making the separate node_modules cache (lines 39–42) redundant and potentially problematic. According to pnpm's official guidance, node_modules should not be cached directly because it contains symlinks to the pnpm store. Caching both separately creates a risk of broken symlinks if the cache restoration order or state becomes inconsistent.

The recommended approach is to rely solely on the pnpm store cache provided by pnpm/action-setup with cache: true. Remove the actions/cache step entirely.

Alternatively, consider using actions/setup-node with cache: 'pnpm' instead, which provides built-in, first-class support for pnpm caching and automatically includes the Node.js version in the cache key to prevent native module compatibility issues.


- name: 📦 Install dependencies (root only, no scripts)
run: pnpm install --filter . --ignore-scripts
run: pnpm install --ignore-scripts

- name: 🔠 Lint project
run: pnpm lint
Expand All @@ -58,6 +63,11 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}

- name: 📦 Install dependencies
run: pnpm install

Expand All @@ -80,6 +90,11 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}

- name: 📦 Install dependencies
run: pnpm install

Expand Down Expand Up @@ -108,6 +123,11 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}

- name: 📦 Install dependencies
run: pnpm install

Expand Down Expand Up @@ -146,6 +166,11 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}

- name: 📦 Install dependencies
run: pnpm install

Expand Down Expand Up @@ -174,6 +199,11 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}

- name: 📦 Install dependencies
run: pnpm install

Expand Down Expand Up @@ -202,6 +232,11 @@ jobs:
with:
cache: true

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}

- name: 📦 Install dependencies
run: pnpm install

Expand Down
Loading