#10542·bit

Installs with the Rust pnpm engine always re-resolve: state-dependent generated manifests and missing dedupePeers option

Author: zkochanCreated Jul 29, 2026Updated Jul 30, 2026

Findings from profiling bd install in the bit2 workspace (331 components, ~8.5k packages) with the Rust pnpm engine (@pnpm/napi). Every install was taking ~4 minutes even with an up-to-date lockfile, and rm -rf node_modules && bd install appeared to hang at Progress: resolved 0, reused N. The engine-side causes are being fixed in pnpm (see references at the bottom); this issue tracks the two findings that need fixes in Bit, because they force the engine into a full re-resolution on every install regardless of how fast the engine is.

1. Generated component manifests differ depending on whether node_modules exists

Bit's dependency detection produces different manifests for the same workspace state depending on the presence of node_modules:

  • with node_modules present, the generated manifests for ui/api-diff-view, ui/hooks/use-bulk-paged-query, and ui/inline-config-compare include @apollo/client@^3.12.0;
  • with node_modules absent, the same components' manifests do not include it — even though all three genuinely import/require @apollo/client in their source.

The engine's lockfile freshness check therefore flaps forever. Captured from the engine's staleness log (TRACE=pacquet::install=info):

  • install with node_modules present, lockfile from a no-node_modules install: specifiers in the lockfile don't match specifiers in package.json: * 1 dependency was added: @apollo/client@^3.12.0
  • install after rm -rf node_modules, lockfile from a with-node_modules install: ... * 1 dependency was removed: @apollo/client@^3.12.0

Because no lockfile can satisfy both states, every install after removing node_modules (and the next one after it is restored) runs a full re-resolution (~3–4 minutes through the engine today) instead of the frozen path. With the flap fixed, the measured frozen path is ~1s of engine time on a warm workspace and ~5.5s of engine materialization after rm -rf node_modules — the "hang" at resolved 0, reused N was the full re-resolution, not the store/link pipeline.

Expected fix: dependency detection / version attribution must be independent of installed state — a component that imports @apollo/client should get the same manifest entry whether or not node_modules exists.

2. lynx.js does not pass dedupePeers: true to the engine

Bit's existing lockfiles record settings.dedupePeers: true (generated by the previous engine integration). The current installOptions built in scopes/dependencies/pnpm/lynx.ts does not pass dedupePeers, so the engine resolves it to its default (false) and its freshness gate reports:

`dedupePeers` in the lockfile (true) doesn't match the current config (false)

→ every install of an existing Bit repo is treated as outdated, full-resolves, and rewrites the entire lockfile's peer suffixes (a ~50k-line diff), which then keeps churning.

Until now this was not fixable from Bit's side because the @pnpm/napi install options did not expose dedupePeers at all; that binding gap is fixed in pnpm/pnpm#13492. Once the @pnpm/napi release containing it ships, lynx.ts should pass dedupePeers: true alongside dedupePeerDependents: true.

Engine-side context (fixed or in progress on the pnpm side)

For completeness — these were found in the same investigation and are not Bit bugs, but they explain the remaining numbers:

  • multi-importer peer-hoist discovery made from-scratch resolution quadratic — fixed and merged (pnpm/pnpm#13491);
  • the per-manifest readPackage hook dispatch cost ~1 event-loop tick per manifest (~200s per full resolve at Bit's scale) — now batched; a quadratic per-package tree scan in the resolver — now indexed; overrides were recorded in random order every install — now order-preserving; all in pnpm/pnpm#13492;
  • remaining engine work (tracked on the pnpm side): resolution executes single-threaded, and lockfile-satisfied picks can still wait on per-package metadata refreshes. A full re-resolution at bit2's scale currently costs ~114s hook-free (~177s with the hook); the goal is double-digit seconds.

With both Bit-side fixes in place, bd install only pays resolution when dependencies actually change; warm repeat installs take ~1s of engine time and rm -rf node_modules && bd install ~5.5s.


Written by an agent (Claude Code, claude-fable-5), investigating together with Zoltan Kochan.