feat: add --no-runtime to skip installing runtime entries#11557
Conversation
Lets users skip the install/link of `devEngines.runtime` entries (e.g. Node.js downloaded via the `runtime:` protocol) without modifying the lockfile. The lockfile keeps the runtime entry so frozen-lockfile validation still passes; only the runtime fetch and `.bin` linking are skipped. Useful in CI matrices where the runtime is provisioned externally before `pnpm install` runs.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🧰 Additional context used📓 Path-based instructions (1)**/*.{js,ts,tsx,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🔇 Additional comments (2)
📝 WalkthroughWalkthroughThis PR adds a ChangesRuntime Skip Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new --no-runtime install flag (config key: runtime=false) to skip installing runtime: protocol dependencies (e.g. Node.js via devEngines.runtime) while keeping the lockfile unchanged so --frozen-lockfile validation still passes.
Changes:
- Add
runtimeboolean config/CLI support and plumb it through install/recursive flows asskipRuntimes. - Update lockfile filtering to drop
runtime:refs from importer dependency maps and prevent runtime packages from being picked into the install set. - Add/extend unit and E2E coverage for
skipRuntimesand--no-runtime.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm/test/install/runtimeOnFail.ts | Adds E2E coverage asserting --no-runtime keeps the lockfile entry but skips .bin creation. |
| lockfile/filtering/test/filterByImportersAndEngine.ts | Adds unit test for skipRuntimes filtering behavior. |
| lockfile/filtering/src/filterLockfileByImportersAndEngine.ts | Plumbs skipRuntimes through filtering and excludes runtime: refs from direct dep paths. |
| lockfile/filtering/src/filterImporter.ts | Extends importer filtering to optionally drop runtime: dependencies. |
| installing/deps-restorer/src/index.ts | Threads skipRuntimes into the lockfile filtering stage for headless installs. |
| installing/deps-installer/src/install/extendInstallOptions.ts | Adds skipRuntimes to strict install options and defaults it to false. |
| installing/commands/src/recursive.ts | Plumbs config runtime into recursive install options and maps it to skipRuntimes. |
| installing/commands/src/installDeps.ts | Plumbs config runtime into install options and maps it to skipRuntimes. |
| installing/commands/src/install.ts | Exposes --no-runtime in help text and rc option typing. |
| config/reader/src/types.ts | Adds runtime as a typed boolean config key. |
| config/reader/src/configFileKey.ts | Marks runtime as excluded from global config file keys list. |
| config/reader/src/Config.ts | Adds runtime?: boolean to the Config interface. |
| .changeset/no-runtime-flag.md | Releases changes across affected packages and documents the new flag. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Reuses the same lockfile filter so both frozen and non-frozen install paths share one mechanism. filterImporter now strips runtime: refs from specifiers as well, so link.ts's specifier-keyed direct-dep linker naturally excludes runtime entries; filterLockfileByImporters walks the already-filtered importers, so packages traversal stops at the runtime boundary too. Adds an e2e test for fresh-checkout install with --no-runtime.
The lockfile filter handles linkPackages (via filtered specifiers) but the direct bin-linking call at the end of _installInContext iterates dependenciesByProjectId and only filters by ctx.skipped. Without this fix, linkBinsOfPackages tries to link the runtime bin (e.g. node.exe) from the store. On Linux it silently created a dangling symlink (which fs.existsSync follows and reports as missing — false-passing the test); on Windows the linker hardlink/copyFile fallback fails with ENOENT. Test now uses lstatSync to catch dangling symlinks.
| reporter: String, | ||
| 'resolution-mode': ['highest', 'time-based', 'lowest-direct'], | ||
| 'resolve-peers-from-workspace-root': Boolean, | ||
| runtime: Boolean, |
Summary
Adds a
--no-runtimeflag (config:runtime: boolean, defaulttrue) that suppresses install of runtime entries declared viadevEngines.runtime(theruntime:protocol) without modifying the lockfile.The lockfile keeps the runtime entry, so frozen-lockfile validation still passes; only the runtime fetch and
.binlinking are skipped. Useful in CI matrices where the runtime is provisioned externally (e.g. viapnpm runtime -g set node <version>) beforepnpm installruns.The existing
--runtime-on-fail=ignoreis unsuitable for this case: it mutates the manifest and regenerates the lockfile to drop the runtime entry, which trips frozen-lockfile validation. The two flags are orthogonal and serve different purposes.Implementation
The hook lives in the lockfile filter stage:
lockfile/filtering/src/filterImporter.ts— stripsruntime:refs from the importer's deps maps whenskipRuntimesis set.lockfile/filtering/src/filterLockfileByImportersAndEngine.ts— newskipRuntimes?: booleanoption; runtime-protocol direct deps are dropped before they enterpickedPackages, so they never reach the dep graph or bin-linker. Applies to all runtimes (node,deno,bun) since they share theruntime:protocol prefix.The option is plumbed through
installing/deps-restorer,installing/deps-installer, andinstalling/commandsto the user-facingpnpm install --no-runtimeflag.Example
Local dev:
pnpm install— installs node 22.13.0 as before.CI matrix entry:
The lockfile is unchanged; the matrix's externally-provisioned node is used.
Test plan
lockfile/filtering/test/filterByImportersAndEngine.tsverifyingskipRuntimes: truestripsruntime:entries from importers and packages while leaving regular deps intact.pnpm/test/install/runtimeOnFail.tsthat runspnpm install(downloads node), wipesnode_modules, runspnpm install --frozen-lockfile --no-runtime, then asserts the lockfile importer entry is unchanged and.bin/nodeis not created.--runtime-on-fail=ignoretest still passes (orthogonal semantics preserved).Written by an agent (Claude Code, claude-opus-4-7).
Summary by CodeRabbit