---
title: "npm 11.18 promeut la stratégie d'installation `linked` en stable, ajoute l'espace de noms `npm install-scripts` et avertit quand `min-release-age` bloque un correctif d'audit"
description: "npm 11.18.0 (29 juin 2026) livre trois fonctionnalités et un long backlog de corrections de bugs qui, ensemble, achèvent le travail que le CLI npm mène sur le mode d'installation `install-strategy=linked` (isolated) depuis la RFC #0042 en 2022. L'événement phare est la [PR #9677](https://github.com/npm/cli/pull/9677) (backport de #9674), qui fait passer `--install-strategy=linked` d'expérimental à stable. Le mode installe chaque paquet dans `node_modules/.store/<name>@<version>/node_modules/<dep>` et lie symboliquement ses dépendances déclarées dans son propre `node_modules/<dep>`, de sorte qu'un paquet ne peut `require` que les dépendances réellement déclarées dans son propre `package.json`. La nouvelle recommandation des docs ([PR #9690](https://github.com/npm/cli/pull/9690)) consiste à exécuter `--install-strategy=linked` en CI pour intercepter les dépendances fantômes avant publication. Autour de cette promotion, la release livre un nouveau namespace `npm install-scripts` ([#9635](https://github.com/npm/cli/pull/9635), backport de #9629) qui possède `approve`, `deny` et `ls`, avec `npm approve-scripts` / `npm deny-scripts` conservés comme alias ; une passe de ménage `install-scripts: prune unused allowScripts entries` ([#9662](https://github.com/npm/cli/pull/9662)) ; et un nouvel avertissement quand `min-release-age` bloque un `npm audit fix` ([#9564](https://github.com/npm/cli/pull/9564)). La release de 43 commits corrige aussi 19 bugs de la stratégie `linked` (déterminisme de l'audit #9638, stubs `.bin` orphelins #9643, nettoyage des `.store` périmés #9649, crash `filterNode` invalide #9645, validation peerOptional #9641), trois fixes `npm sbom` et un fix d'encodage en pourcentage du qualificateur `vcs_url` dans les purls générées ([#9693](https://github.com/npm/cli/pull/9693))."
date: 2026-06-30
image: "/images/heroes/2026-06-30--npm-11-18-linked-install-strategy-stable-phantom-deps.png"
author: lschvn
tags: ["tooling", "ecosystem"]
tldr:
  - "[npm 11.18.0](https://github.com/npm/cli/releases/tag/v11.18.0) (29 juin 2026) fait passer `--install-strategy=linked` d'expérimental à stable via la [PR #9677](https://github.com/npm/cli/pull/9677), backport de la [PR #9674](https://github.com/npm/cli/pull/9674). Le mode avait été ajouté dans la [PR #6078](https://github.com/npm/cli/pull/6078) le 25 janvier 2023 contre la RFC [npm/rfcs#0042](https://github.com/npm/rfcs/blob/main/accepted/0042-isolated-mode.md) et était resté tagué expérimental depuis. La promotion retire l'avertissement implicite « ceci peut dévorer votre node_modules » que la doc portait depuis trois ans et demi, et constitue l'événement de clôture du travail sur le mode isolated que l'équipe npm avait lancé au Contributor Summit 2022."
  - "La release livre le nouvel espace de noms de commande `npm install-scripts` ([#9635](https://github.com/npm/cli/pull/9635), backport de [#9629](https://github.com/npm/cli/pull/9629)) qui possède `approve`, `deny` et `ls`. Les anciennes commandes `npm approve-scripts` et `npm deny-scripts` sont conservées comme alias pour une release. La release ajoute aussi `install-scripts: prune unused allowScripts entries` ([#9662](https://github.com/npm/cli/pull/9662)), `npm sbom` encode en pourcentage le qualificateur `vcs_url` dans les purls générées ([#9693](https://github.com/npm/cli/pull/9693)), et `npm audit fix` avertit désormais explicitement quand `minimumReleaseAge` bloque le correctif qu'il appliquerait sinon ([#9564](https://github.com/npm/cli/pull/9564))."
  - "Autour de la promotion, 19 des 43 commits sont des corrections de bugs pour la stratégie `linked` elle-même : déterminisme de l'audit sous linked (#9638), audit de l'arbre non-isolé sous la stratégie linked (#9631), stubs `.bin` orphelins après uninstall (#9643), nettoyage des `.store` et hoisted périmés au changement de stratégie (#9649), crash `filterNode` invalide (#9645), réparation de cible de symlink existante mais incorrecte (#9644), validation peerOptional dans les mutations no-save (#9641), `npm exec` qui résout les bins locaux au workspace sous linked (#9648), et `npm query` qui reporte l'emplacement logique des deps sous linked (#9664). Prises ensemble, ces corrections font de `linked` une alternative viable à la stratégie par défaut `hoisted` pour le développement quotidien, et plus seulement pour les smoke-tests en CI."
faq:
  - question: "Que change concrètement la stratégie d'installation `linked` ?"
    answer: "La stratégie par défaut `hoisted` duplique les dépendances transitives dans le `node_modules` de niveau racine pour que tout paquet puisse `require` n'importe quelle dépendance transitive hissée par hasard, même si rien dans son `package.json` ne la déclare. C'est la cause racine des dépendances fantômes : du code qui importe une bibliothèque jamais ajoutée à ses propres `dependencies`, et le bug n'apparaît que lorsqu'un collègue installe avec un `node_modules` propre et que le hissage se trouve différent. `--install-strategy=linked` (aussi appelée mode isolated) installe en revanche chaque paquet dans `node_modules/.store/<name>@<version>/node_modules/<dep>` et lie symboliquement les dépendances déclarées de chaque paquet dans son propre `node_modules/<dep>`. Résultat : un paquet ne peut `import` que ce qu'il a déclaré. S'il importe une bibliothèque non déclarée, l'import échoue immédiatement au lieu de fonctionner par accident et de partir en prod cassé."
  - question: "Pourquoi est-ce important si la stratégie existe depuis 2023 ?"
    answer: "Trois raisons. D'abord, la stratégie était taguée expérimentale depuis trois ans et demi, ce qui donnait à la plupart des équipes une bonne raison de ne pas en dépendre en production : une stratégie stable est une stratégie qu'on peut poser dans `~/.npmrc` et oublier. Ensuite, le drapeau expérimental s'accompagnait d'angles tranchants : l'audit était peu fiable sous linked (#9609), `npm ls` reportait des `UNMET DEPENDENCY` fantômes (#9095), `npm install --audit` renvoyait zéro résultat sur une vulnérabilité réelle (#9609), et `napi-postinstall` ne parvenait pas à résoudre une liaison native optionnelle installée (#9620). Les 19 corrections de bugs de la 11.18 referment ces failles. Enfin, la doc npm recommande désormais activement `linked` pour les auteurs de paquets en CI ([PR #9690](https://github.com/npm/cli/pull/9690)) : la page de doc dit « Nous recommandons aux auteurs de paquets d'utiliser --install-strategy=linked pendant le développement pour intercepter les dépendances non déclarées (`phantom`) avant publication »."
  - question: "Qu'est-ce que `npm install-scripts` et qu'est-ce que ça change pour moi ?"
    answer: "`npm install-scripts` est un nouvel espace de noms de commande de niveau racine introduit par la [PR #9635](https://github.com/npm/cli/pull/9635) (backport de [#9629](https://github.com/npm/cli/pull/9629)). Il possède trois sous-commandes : `npm install-scripts approve`, `npm install-scripts deny` et `npm install-scripts ls`. Les anciennes commandes `npm approve-scripts` et `npm deny-scripts` sont conservées comme alias pour une release, puis retirées. Le namespace ré-oriente aussi les instructions d'install, de rebuild et de strict-allow-scripts vers les nouvelles commandes. La raison d'être du namespace est que `approve-scripts` était une commande cas spécial posée à côté du reste de la surface de commandes npm ; `install-scripts` la fait entrer dans la même famille que `install`, `install-test`, etc. La release ajoute aussi `install-scripts: prune unused allowScripts entries` ([#9662](https://github.com/npm/cli/pull/9662)) pour que la liste d'allow se réduise quand des paquets sont retirés de `dependencies`."
  - question: "Que fait le nouvel avertissement `min-release-age` sur l'audit fix ?"
    answer: "La [PR #9564](https://github.com/npm/cli/pull/9564) (backport de [#9544](https://github.com/npm/cli/pull/9544)) apprend à `npm audit fix` à détecter quand le correctif qu'il appliquerait est bloqué par la policy `minimumReleaseAge` configurée dans `.npmrc` (la même policy qu'[Astro 6.4.4](/articles/2026-06-05--astro-6-4-4-routing-i18n-dev-fixes) surface dans son propre flux de mise à jour). Quand le correctif est bloqué par la policy, npm 11.18 imprime un avertissement explicite qui dit quel paquet serait sauté et quel drapeau de policy le bloque, au lieu de ne rien faire en silence. La même policy a été livrée dans [pnpm 11.8](/articles/2026-06-19--pnpm-11-8-dry-run-install-node-package-map-sbom) et fait désormais partie de la baseline de tout gestionnaire de paquets qui veut se coordonner avec les propriétaires de monorepos qui imposent un délai de refroidissement aux nouvelles releases."
  - question: "Comment cela se compare-t-il à pnpm et yarn ?"
    answer: "pnpm utilise un layout isolated par défaut depuis la première release du projet en 2017 et n'a jamais porté le drapeau expérimental : tout paquet ne peut `require` que ce qu'il déclare, et les dépendances fantômes sont impossibles par construction. Yarn berry (Yarn 2+) livre un mode similaire `nodeLinker: pnp` et un réglage `nmHoistingLimits` qui approxime l'isolation. Le mode `linked` de npm est l'équivalent npm de ces deux approches, et la 11.18 est la release où npm accepte de le recommander comme stratégie quotidienne pour les auteurs de paquets, exactement comme le fait pnpm. Les trois gestionnaires sont désormais d'accord sur le modèle d'installation ; la différence est celui qui est la valeur par défaut : pnpm (isolated, jamais expérimental), yarn berry (PnP par défaut, hoisted opt-in), npm hoisted (linked opt-in)."
  - question: "Est-il sûr de passer à npm 11.18 dès aujourd'hui ?"
    answer: "Pour la grande majorité des projets, oui : la stratégie par défaut `hoisted` reste inchangée, les changements de surface CLI sont additifs (nouveau namespace `npm install-scripts`, alias conservés pour une release), et les chemins SBOM, audit et `npm ls` reçoivent des corrections qui améliorent la correctness. Les deux raisons d'attendre sont (1) votre projet dépend d'un paquet qui utilise un hook d'installation d'une façon que le nouvel audit strict-allow-scripts traite comme inerte et signale ; l'[article sur la supply chain npm du 6 juin](/articles/2026-06-06--npm-supply-chain-attack-red-hat-mini-shai-hulud) couvre les drapeaux pertinents et (2) vous utilisez intensivement `npm link` contre un workspace qui a son propre `.store`, où le nettoyage au changement de stratégie ([#9649](https://github.com/npm/cli/pull/9649)) est un changement de comportement plutôt qu'une correction de bug. Pour tous les autres, `npm install -g npm@11` et le nouveau mode `linked` constituent une mise à niveau d'un seul drapeau."
---

[npm 11.18.0](https://github.com/npm/cli/releases/tag/v11.18.0), publiée le 29 juin 2026, est la release qui achève le travail que le CLI npm mène sur les installations isolées depuis trois ans et demi. L'événement phare est la [PR #9677](https://github.com/npm/cli/pull/9677) (backport de [#9674](https://github.com/npm/cli/pull/9674)), qui fait passer `--install-strategy=linked` d'expérimental à stable. Le mode avait été ajouté dans la [PR #6078](https://github.com/npm/cli/pull/6078) le 25 janvier 2023 contre la [npm/rfcs#0042](https://github.com/npm/rfcs/blob/main/accepted/0042-isolated-mode.md), la RFC sur le mode isolated issue du Contributor Summit 2022. La promotion retire l'avertissement implicite « ceci peut dévorer votre node_modules » que la doc portait depuis 2023 et constitue l'événement de clôture du plus long effort de l'équipe npm sur les stratégies d'installation.

La release est la deuxième release de fonctionnalité de la ligne v11 ce mois-ci et accompagne la [prerelease npm v12](https://github.com/npm/cli/releases/tag/v12.0.0-pre.2) que l'équipe a taguée le même jour. La ligne v11 est la ligne stable ; la prerelease v12 est l'endroit où le [changement block-unreviewed-install-scripts-by-default](https://github.com/npm/cli/pull/9424) et la [promotion du mode linked](https://github.com/npm/cli/pull/9674) sont ré-appliqués contre la future major.

## Ce que `--install-strategy=linked` change concrètement

La stratégie d'installation par défaut de npm est `hoisted`. Chaque dépendance transitive est dupliquée dans le `node_modules` racine pour que tout paquet puisse `require` n'importe quelle dépendance transitive hissée par hasard, même si rien dans son `package.json` ne la déclare. C'est la cause racine des dépendances fantômes : du code qui importe une bibliothèque jamais ajoutée à ses propres `dependencies`, et le bug n'apparaît que lorsqu'un collègue installe avec un `node_modules` propre et que le hissage se trouve différent.

`--install-strategy=linked` (aussi appelée mode isolated) installe en revanche chaque paquet dans `node_modules/.store/<name>@<version>/node_modules/<dep>` et lie symboliquement les dépendances déclarées de chaque paquet dans son propre `node_modules/<dep>`. Résultat : un paquet ne peut `import` que ce qu'il a déclaré. S'il importe une bibliothèque non déclarée, l'import échoue immédiatement au lieu de fonctionner par accident et de partir en prod cassé.

La [doc npm install](https://docs.npmjs.com/cli/v11/commands/npm-install#install-strategy) décrit les quatre stratégies ainsi :

- `hoisted` (défaut) : installe non-dupliqué au niveau racine, dupliqué si nécessaire au sein de la structure de répertoires.
- `nested` (anciennement `--legacy-bundling`) : installe en place, sans hissage.
- `shallow` (anciennement `--global-style`) : n'installe que les deps directes au niveau racine.
- `linked` : installe dans `node_modules/.store`, lie en place, pas de hissage.

Les notes de release de la 11.18 ajoutent la recommandation de doc qui fait de la stratégie une vraie recommandation plutôt qu'un flag CLI caché. La page de doc dit désormais : « Nous recommandons aux auteurs de paquets d'utiliser `--install-strategy=linked` pendant le développement pour intercepter les dépendances non déclarées (`phantom`) avant publication : le layout isolated n'expose que les dépendances déclarées du paquet, donc un `import` d'un paquet qui n'a jamais été ajouté au `package.json` peut échouer au lieu de se résoudre par accident et de partir cassé. Voir [Catching undeclared (`phantom`) dependencies](/cli/v11/using-npm/developers#catching-undeclared-phantom-dependencies). »

Cette phrase a été ajoutée par la [PR #9690](https://github.com/npm/cli/pull/9690), le changement de doc qui backporte en parallèle de la promotion.

## Pourquoi trois ans et demi en expérimental

Trois raisons. D'abord, le drapeau expérimental s'accompagnait d'angles tranchants. Le [ticket de suivi #9608](https://github.com/npm/cli/issues/9608) de l'équipe (`[Tracking] install-strategy=linked (isolated mode) bugs`) liste 19 bugs distincts à travers le chemin d'install, le chemin d'audit, le chemin `npm exec` et le chemin `npm ls` que la release 11.18 referme. Les quatre que l'équipe a signalés comme les pires sont [l'audit qui renvoie zéro résultat sur une vulnérabilité réelle](https://github.com/npm/cli/issues/9609) (#9609), [`npm ls` qui reporte de faux `UNMET DEPENDENCY`](https://github.com/npm/cli/issues/9095) (#9095), [`napi-postinstall` qui ne résout pas une liaison native optionnelle installée](https://github.com/npm/cli/issues/9620) (#9620), et le [mismatch de layout `.store` avec le lockfile caché](https://github.com/npm/cli/issues/9612) (#9612). Les fixes 11.18 pour chacun sont les PRs #9638, la suite de #9095 sous la logique de #9638, le fix de #9620 sous #9665, et #9642 respectivement.

Ensuite, la stratégie avait besoin d'une histoire d'audit. La [PR #9625](https://github.com/npm/cli/pull/9625) audit l'arbre non-isolé sous la stratégie linked, de sorte que `npm audit` parcourt à la fois la vue linked et le store sous-jacent et reporte les vulnérabilités correctement. La [PR #9638](https://github.com/npm/cli/pull/9638) rend le rapport d'audit déterministe en rattachant les liens `via` perdus, pour que deux exécutions consécutives de `npm audit` sur un lockfile inchangé produisent une sortie octet-identique, ce dont l'infrastructure CI de l'équipe dépend pour les tests de régression basés sur diff.

Enfin, l'histoire workspace. Les [PR #9666](https://github.com/npm/cli/pull/9666) et [#9665](https://github.com/npm/cli/pull/9665) apprennent à la stratégie linked à charger les dépendances optionnelles transitives et à appliquer correctement les drapeaux `dev`/`prod` au sein des workspaces ; [#9648](https://github.com/npm/cli/pull/9648) fait que `npm exec` résout les bins locaux au workspace ; [#9669](https://github.com/npm/cli/pull/9669) surface les workspaces non déclarés sous la stratégie linked pour qu'une entrée `workspaces` manquante ne produise pas silencieusement une install partielle. Avant la 11.18, la stratégie linked fonctionnait pour les repos mono-paquet mais trébuchait sur les setups workspaces ; après la 11.18, c'est le pilote quotidien recommandé pour les workspaces.

## Le nouvel espace de noms `npm install-scripts`

La [PR #9635](https://github.com/npm/cli/pull/9635) (backport de [#9629](https://github.com/npm/cli/pull/9629)) introduit une commande à espace de noms `npm install-scripts` qui possède trois sous-commandes : `npm install-scripts approve`, `npm install-scripts deny`, et `npm install-scripts ls`. Les anciennes commandes `npm approve-scripts` et `npm deny-scripts` sont conservées comme alias pour une release, puis retirées. Le namespace ré-oriente les instructions d'install, de rebuild et de strict-allow-scripts vers les nouvelles commandes, pour qu'un développeur qui exécute `npm install` et tombe sur la nouvelle ligne « npm install blocked N scripts » soit renvoyé vers la même famille de commandes.

La raison d'être du namespace est que `approve-scripts` était une commande cas spécial posée à côté du reste de la surface de commandes npm ; `install-scripts` la fait entrer dans la même famille que `install`, `install-test`, etc. Cela donne aussi à l'équipe la place d'ajouter des sous-commandes : `npm install-scripts ls` est nouveau en 11.18 et imprime la liste allow/deny courante avec les noms de paquets et les chemins.

La release ajoute aussi la [PR #9662](https://github.com/npm/cli/pull/9662) (`install-scripts: prune unused allowScripts entries`), qui balaie la liste d'allow à chaque install et retire les entrées dont le paquet n'est plus dans `dependencies`. Cela referme un défaut de longue date où la liste d'allow croissait monotonement : si vous approuviez `esbuild` pour `package-a`, puis retiriez `esbuild` des deps de `package-a` et l'ajoutiez à celles de `package-b`, la liste d'allow gardait l'entrée d'origine. Après la 11.18, le sweep la retire dans `npm install`, et l'utilisateur est invité à réapprouver sous `package-b`.

## L'avertissement `min-release-age` sur l'audit fix

La [PR #9564](https://github.com/npm/cli/pull/9564) (backport de [#9544](https://github.com/npm/cli/pull/9544)) apprend à `npm audit fix` à détecter quand le correctif qu'il appliquerait est bloqué par la policy `minimumReleaseAge` configurée dans `.npmrc`. La même policy est livrée par [pnpm](https://pnpm.io/npmrc#minimum-release-age), et le flux de mise à jour d'[Astro 6.4.4](/articles/2026-06-05--astro-6-4-4-routing-i18n-dev-fixes) la surface pour `@astrojs/upgrade`. La version npm avertit explicitement quand la policy bloque un correctif d'audit, au lieu de ne rien faire en silence :

```
npm audit fix
# 3 vulnerabilities (1 low, 1 moderate, 1 high)
#
# Could not auto-fix 1 vulnerability:
#   package: glob-parent <6.0.0 (transitive via some-tool)
#   blocked by minimumReleaseAge=4320 (cool-down window)
#   set `minimum-release-age=0` or wait for the cool-down to expire.
```

Le texte a la même forme que l'avertissement `ERR_PNPM_MIN_RELEASE_AGE` de pnpm. La description de PR de l'équipe npm dit qu'elle « veut que les utilisateurs puissent faire la différence entre « pas de correctif disponible » et « correctif existant mais retenu par la policy » », ce que la sortie précédente de `npm audit fix` ne permettait pas.

## SBOM et autres corrections

Trois fixes `npm sbom` sont livrés en 11.18. La [PR #9693](https://github.com/npm/cli/pull/9693) encode en pourcentage le qualificateur `vcs_url` dans les purls générées, ce qui referme un bug de longue date de l'outillage CP où une URL `git+https://github.com/foo bar/bar` (avec un espace) était émise verbatim et rejetée par les parseurs en aval. La [#9631](https://github.com/npm/cli/pull/9631) audit l'arbre non-isolé sous la stratégie linked pour que les rapports SBOM et `npm audit` remontent tous les deux le jeu complet de deps. La [#9641](https://github.com/npm/cli/pull/9641) valide les conflits `peerOptional` dans les mutations no-save, ce qui signifie que `npm install some-pkg --no-save` refusera d'installer si cela créerait un conflit peerOptional.

La release corrige aussi la [PR #9602](https://github.com/npm/cli/pull/9602) (ne pas signaler les deps optionnelles inertes en `strict-allow-scripts`), la [#9607](https://github.com/npm/cli/pull/9607) (approuver par nom les deps sans URL résolue), et la [#9663](https://github.com/npm/cli/pull/9663) (refermer les failles d'enforcement allowScripts). Prises ensemble, elles signifient que le mode `strict-allow-scripts` ajouté dans [npm 11.5](/articles/2026-06-06--npm-supply-chain-attack-red-hat-mini-shai-hulud) distingue maintenant correctement les paquets qui ont besoin de scripts (le hook d'install est actif, le hook d'audit les attrapera) et ceux qui n'en ont pas (le hook d'install est désactivé parce qu'il n'y a pas de script d'install).

## Pourquoi c'est important

`--install-strategy=linked` est la réponse de npm à la question à laquelle pnpm répond depuis 2017 : comment empêcher un paquet d'importer une dépendance transitive qu'il n'a jamais déclarée ? pnpm n'a jamais porté le drapeau expérimental ; yarn berry livre PnP par défaut ; npm est le troisième des trois à atteindre le statut « stable et recommandé pour l'usage quotidien ». La promotion est le moment où le modèle d'installation que tous les autres traitent comme défaut devient enfin un chemin recommandé par défaut chez npm.

Pour les auteurs de paquets, le changement concret est petit et précis. Ajoutez ceci à `.npmrc` :

```
install-strategy=linked
```

Puis exécutez `npm install` en CI dans le cadre du `npm publish`. Si le build échoue maintenant parce qu'un fichier de test importe une bibliothèque non déclarée, vous avez un vrai bug à corriger avant publication, pas une dépendance fantôme qui explosera sur l'install propre d'un collègue.

Le même changement s'applique aux propriétaires de monorepos. Les fixes 11.18 pour `npm exec` (#9648), `npm ls` (#9664), les workspaces (#9666), et le nettoyage `.store` au changement de stratégie (#9649) referment les failles qui rendaient `--install-strategy=linked` inutilisable pour les workspaces avant. Un monorepo peut livrer `install-strategy=linked` dans `.npmrc` à la racine et compter sur sa propagation dans les workspaces.

La release est aussi la première depuis l'[article supply chain du 6 juin](/articles/2026-06-06--npm-supply-chain-attack-red-hat-mini-shai-hulud) qui referme les failles d'audit strict-allow-scripts mentionnées dans cet article. Les drapeaux `--install-blocked-scripts` et `strict-allow-scripts` de npm 11.5 sont maintenant utilisables de bout en bout, et le nouvel espace de noms `npm install-scripts` est l'endroit où vivent les approbations.