From a50890f76721e17a4d9a6f1fd987228bcdb10cbe Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Fri, 26 Jun 2026 22:31:13 +0530 Subject: [PATCH] feat: graduate the linked install strategy from experimental to stable (#9674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the experimental designation from `install-strategy=linked` (isolated mode): drops the install-time warning and the `(experimental)` note in the config docs. `linked` is now a supported, opt-in install strategy. The default stays `hoisted`. ## Why `install-strategy=linked` (RFC-0042) has been experimental since it shipped, warning on every install. It has since been hardened extensively — the discrepancies tracked in #9608, plus ~50 earlier PRs, are resolved — and it now produces hoisted-equivalent results across `install`/`ci`/`ls`/`query`/`explain`/`audit`/`sbom`/`exec`/`run`/`link`/`uninstall`, the supply-chain controls (`allow-scripts`/`allow-remote`/`allow-git`, `--strict-allow-scripts`), and the v12 features (`npm patch`, `packageExtensions`, `.npm-extension`), with a project lockfile identical to hoisted. It has also been exercised against the [Gutenberg monorepo](https://github.com/WordPress/gutenberg/pull/75814), which powers the WordPress Block Editor. The experimental warning no longer reflects its state. ## How - `@npmcli/arborist` (`reify.js`): remove the `The "linked" install strategy is EXPERIMENTAL and may contain bugs.` warning emitted on every linked install. - `@npmcli/config` (`definitions.js`): drop `(experimental)` from the `install-strategy` description for `linked`. - Regenerate the config docs snapshot to match. The `node_modules/.store/` layout remains an internal implementation detail. This does not change the default install strategy. ## References - Hardening tracked in #9608 - RFC-0042 (isolated mode): https://github.com/npm/rfcs/blob/main/accepted/0042-isolated-mode.md (cherry picked from commit 86416a626e4599791c5d8115ed08aa4369774844) --- tap-snapshots/test/lib/docs.js.test.cjs | 4 ++-- workspaces/arborist/lib/arborist/reify.js | 1 - workspaces/config/lib/definitions/definitions.js | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index 9496bc714a10a..a4c1e235ed784 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -1089,8 +1089,8 @@ Sets the strategy for installing packages in node_modules. hoisted (default): Install non-duplicated in top-level, and duplicated as necessary within directory structure. nested: (formerly --legacy-bundling) install in place, no hoisting. shallow (formerly --global-style) only install direct -deps at top-level. linked: (experimental) install in node_modules/.store, -link in place, unhoisted. +deps at top-level. linked: install in node_modules/.store, link in place, +unhoisted. diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 1f90c117a45cd..6b5ab00269a84 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -124,7 +124,6 @@ module.exports = cls => class Reifier extends cls { // swap out the tree with the isolated tree // this is currently technical debt which will be resolved in a refactor // of Node/Link trees - log.warn('reify', 'The "linked" install strategy is EXPERIMENTAL and may contain bugs.') this.idealTree = await this.createIsolatedTree() isolatedTree = this.idealTree if (this.actualTree) { diff --git a/workspaces/config/lib/definitions/definitions.js b/workspaces/config/lib/definitions/definitions.js index 7c922121eee14..ed1a25bf93a34 100644 --- a/workspaces/config/lib/definitions/definitions.js +++ b/workspaces/config/lib/definitions/definitions.js @@ -1208,8 +1208,7 @@ const definitions = { necessary within directory structure. nested: (formerly --legacy-bundling) install in place, no hoisting. shallow (formerly --global-style) only install direct deps at top-level. - linked: (experimental) install in node_modules/.store, link in place, - unhoisted. + linked: install in node_modules/.store, link in place, unhoisted. `, flatten, }),