Skip to content
Fran Gonzalez
← Back to blog
(updated Sep 30, 2026)·Clanker·2 min read

pnpm 12 audit is CPU-bound, not network-bound

pnpm audit got ~60x slower in 12.x and the fix starts with checking user CPU time, not the registry.

Some matmuls wrote this slop, sorry. My goal with this content is to document some work I (a real human bean) do while poking the Clanker, and try to learn something along the way.

After upgrading to pnpm 12.3.4, pnpm audit jumped from ~2.8s to ~178s in CI. The wall time was user CPU rather than network latency, spent in the single-threaded native binary that bin/pnpm.mjs spawnSyncs (@pnpm/exe.<platform>/pnpm).

Note

Tested with pnpm 11.25.0 and pnpm 12.3.4 on macOS (arm64) on 2026-09-07.

What I Learned

Comparing wall versus user time on the same lockfile shows the shift:

/usr/bin/time pnpm@11.25.0  audit --prod --audit-level high
# real 0.73s  user 0.38s

/usr/bin/time pnpm@12.3.4   audit --prod --audit-level high
# real 32.00s user 31.39s   ← CPU-bound, not I/O

User ≈ real means the process is computing, not waiting on the network. ps confirms one core pinned at 100% in the native child while the Node shim idles in kevent.

Bisecting by pruning importer dep edges from a copy of the lockfile (edges out, never entries (deleting packages:/snapshots: entries breaks lockfile references)) produced a minimal repro: one importer dep, expo-dev-client, same lockfile, same machine.

# lockfile with a single dependency: expo-dev-client
pnpm@11.25.0 audit --prod --audit-level high   # 0.73s
pnpm@12.3.4  audit --prod --audit-level high   # 9.61s, 100% of one core

With all 83 of that importer’s dependencies restored, the same file takes 0.67s on 11.25.0 and 31.61s on 12.3.4. --json narrows the trigger further: pnpm 12 is only slow when an advisory actually matches (metadata.vulnerabilities.moderate: 1 for expo-dev-client). No match, fast. Match, and it enumerates dependency paths for the finding through the whole graph (expo-dev-client resolves to 730 total deps, 272 optional), the same diamond-path behavior documented in pnpm issue #12086, whose fix landed in 11.5.1/11.9.0.

Notes

  • --loglevel debug and --reporter ndjson print nothing per-phase for audit; the native binary also ignores NODE_OPTIONS, so --cpu-prof dies at the shim.
  • Next diagnostic step when the binary hides the JS: run the CLI from the pnpm repo source under node --cpu-prof.
  • An earlier per-dep timing of mine flagged @powersync/react-native as a second heavy dep; repeated runs showed it fast on both majors (0.34s to 0.47s). Verify anomalous timings before building a story on them.

References

This post was written with AI assistance.