Dans les coulisses de la réécriture de pnpm en Rust
Découvrez la réécriture de pnpm 12 en Rust, ses résultats de benchmark, sa compatibilité avec pnpm 11 et les risques de mise à niveau pour la CI.
pnpm 12 remplace la base de code TypeScript de pnpm par une réécriture native en Rust. Il conserve les commandes, les options, les paramètres et le format de lockfile de pnpm 11, si bien que la plupart des projets peuvent migrer sans modifier la moindre configuration.
Si vous utilisez pnpm sur un monorepo et un parc de CI très sollicité, vous avez sans doute vu passer des titres annonçant « 90 % plus rapide » et vous vous êtes demandé où était le piège. Une nouvelle version majeure de l’outil qui écrit votre lockfile mérite un examen plus attentif qu’un simple graphique de benchmark.
Cet article explique pourquoi un gestionnaire de paquets écrit en JavaScript est lent, ce que le moteur Rust a changé et ce qu’il a coûté, qui a mesuré chaque chiffre, et quels changements de comportement peuvent affecter votre pipeline.
Points clés
- pnpm 12.0.0 est passé en version stable le 26 août 2026. Il conserve les commandes, les options, les paramètres et le format de lockfile de pnpm 11, à l’exception d’une courte liste de différences documentées.
- Sur la page de benchmarks officielle de pnpm (pnpm 11.27.1 contre 12.7.0), une réinstallation à chaud passe de 563 ms à 18 ms. Une installation propre ne passe en revanche que de 8,4 s à 4,4 s, car le transfert réseau et la décompression dominent les installations à froid.
- Vercel a mesuré que son workspace de 1 670 paquets s’installait en 64,4 % à 90,5 % de temps en moins avec pnpm 12 qu’avec pnpm 10.28. Le démarrage via Corepack sans cache est toutefois devenu 11,1 % plus lent, en raison du poids accru du binaire natif à télécharger.
- Le changement le plus susceptible de casser votre CI est la suppression de
pnpm install --resolution-only. Utilisezpnpm peers checkà la place.
La contrainte : le même pnpm, un moteur différent
pnpm 12 a été conçu pour que la mise à niveau ne ressemble pas à une migration. L’annonce de la version 12.0 de pnpm en fait son objectif, et le guide de compatibilité confirme qu’à une courte liste de différences près, pnpm 12 conserve les commandes, les options, les paramètres et le format de lockfile de pnpm 11. pnpm 12 conserve également le store adressable par contenu, qui permet aux projets de partager les fichiers des paquets au lieu de les copier. Selon InfoQ, la structure de node_modules reste elle aussi inchangée.
La plupart des réécritures voient dans la nouvelle base de code l’occasion de corriger d’anciens choix de conception. pnpm a fait de la compatibilité son objectif, au point d’affirmer que sa documentation s’applique aux deux versions. En surface, presque rien n’a changé. Tout le travail a consisté à remplacer ce qui se trouve en dessous.
Pourquoi un gestionnaire de paquets JavaScript est-il lent ?
Un gestionnaire de paquets écrit en JavaScript paie deux coûts à chaque installation d’envergure. Il démarre le runtime Node.js à chaque invocation, et il fait transiter des milliers d’opérations sur le système de fichiers par un unique runtime JavaScript.
Une installation se déroule à peu près selon les phases suivantes :
- Récupération des métadonnées des paquets depuis le registre.
- Résolution du graphe de dépendances.
- Téléchargement des tarballs.
- Décompression dans le store.
- Liaison des paquets dans
node_modules.
Le premier coût est fixe. Avant que pnpm 11 n’effectue le moindre travail utile, Node.js devait démarrer. pnpm 12 est publié sous forme de binaires natifs, avec un paquet @pnpm/exe.<platform>-<arch> par plateforme. La documentation de self-update confirme que rien ne lance Node.js au préalable : ce coût de démarrage disparaît donc.
Le second coût croît avec la charge de travail. Les phases 4 et 5 impliquent de décompresser des tarballs et de créer des milliers de liens physiques (hard links), et chacune de ces opérations passe par le runtime JavaScript.
Le principe vaut pour n’importe quel outil : supprimer un surcoût fixe est surtout bénéfique lorsqu’il reste peu d’autre travail à accomplir. Quand une installation n’a presque rien à faire, le démarrage représente l’essentiel du temps d’exécution réel. Quand elle doit télécharger des centaines de mégaoctets, le démarrage devient négligeable.
pnpm 12 est-il vraiment plus rapide ?
Les gains de vitesse de pnpm 12 sont réels mais inégaux : une réinstallation à chaud passe de 563 ms à 18 ms, tandis qu’une installation propre ne passe que de 8,4 s à 4,4 s. Ces gains proviennent de deux séries de mesures distinctes, avec des références différentes. Ne les fusionnez pas en un seul chiffre.
| Scénario | Avant | pnpm 12 | Mesuré par | Référence |
|---|---|---|---|---|
| Réinstallation à chaud | 563 ms | 18 ms | Page de benchmarks de pnpm (pnpm 12.7.0) | pnpm 11.27.1 |
| Installation propre | 8,43 s | 4,42 s | Page de benchmarks de pnpm (pnpm 12.7.0) | pnpm 11.27.1 |
| Workspace de 1 670 paquets, six scénarios (médiane) | n.d. | 64,4 à 90,5 % de temps en moins | Vercel (pnpm 12.0.0) | pnpm 10.28.0 |
| Démarrage Corepack sans cache | n.d. | 11,1 % plus lent | Vercel (pnpm 12.0.0) | pnpm 10.28.0 |
| Démarrage Corepack avec cache | n.d. | 74,7 % plus rapide | Vercel (pnpm 12.0.0) | pnpm 10.28.0 |
Les chiffres de pnpm concernent le projet alotta-files sur la page de benchmarks de pnpm, qui compare pnpm 11.27.1 à pnpm 12.7.0. Cette page est régulièrement mise à jour et affiche toujours la version la plus récente de chaque outil : attendez-vous donc à ce que ces chiffres évoluent. L’écart entre les deux lignes pnpm illustre concrètement la section précédente. L’installation à chaud est environ 30 fois plus rapide, très probablement parce que les coûts fixes, comme le démarrage, représentaient une part importante de son temps d’exécution. L’installation propre n’est qu’environ 1,9 fois plus rapide, car le transfert réseau et la décompression des tarballs occupent l’essentiel du temps, quel que soit le langage du moteur.
Les mesures de Vercel révèlent la même tendance. Avec un node_modules déjà présent, un store chaud et les scripts désactivés, les installations sont passées de 1,476 s à 142 ms. Une installation entièrement à froid, scripts de cycle de vie activés, est passée de 9,850 s à 3,472 s. Chaque médiane est issue de 20 exécutions par version sur une même machine Linux, dans un workspace Turborepo de 21 projets.
Le build natif de pnpm 12 a un coût. Vercel évalue le téléchargement Corepack de pnpm 12 à 47,3 Mo, contre 17,5 Mo pour pnpm 10.28.0, et attribue le ralentissement du démarrage sans cache à ce téléchargement plus volumineux. Les runners de CI qui ne mettent pas Corepack en cache paieront probablement ce surcoût à chaque job.
La gestion déterministe des cycles, livrée en même temps que le nouveau moteur, constitue un gain distinct. Le guide de compatibilité de pnpm attribue à ce changement, et non au moteur Rust lui-même, une consommation mémoire réduite d’environ 25 % et une résolution des peer dependencies 2 à 3 fois plus rapide sur les workspaces comportant de nombreux cycles.
La page de benchmarks publique de pnpm ne compare désormais pnpm 12 qu’à npm et à pnpm 11. Selon InfoQ, pnpm a retiré Bun et Yarn de la comparaison après que des problèmes de configuration du benchmark ont rendu ces classements peu fiables.
Pourquoi le format du lockfile de pnpm devait-il rester identique ?
Le format du lockfile de pnpm 12 devait rester le même, car une rupture à ce niveau aurait divisé les équipes en pleine mise à niveau. Si pnpm 12 avait écrit un nouveau format, chaque poste de développement et chaque runner de CI aurait dû basculer le même jour. Faute de quoi, deux dialectes de lockfile se seraient affrontés dans un même dépôt, et chaque pull request aurait embarqué du bruit généré par la dernière version exécutée.
Conserver le format vise à permettre une mise à niveau progressive au sein d’une équipe. Cela ne signifie pas pour autant que le contenu du fichier ne changera jamais. Le format et le contenu sont deux choses distinctes :
- Les lockfiles existants continuent de fonctionner. Le guide précise que pnpm ne modifie pas les entrées existantes tant qu’aucun élément ne l’oblige à les résoudre de nouveau.
- Une nouvelle résolution peut modifier certaines entrées. pnpm 12 enregistre les dépendances provenant de GitHub, GitLab et Bitbucket sous leur URL HTTPS, jamais sous une URL SSH. Il coupe également les cycles de dépendances toujours au même endroit, ce qui réduit la taille des lockfiles dans les workspaces comportant de nombreux cycles.
Examinez le diff produit par votre première installation avec nouvelle résolution sous pnpm 12 dans un commit dédié.
Qu’est-ce qui casse lors de la migration vers pnpm 12 ?
Si la mise à niveau vers pnpm 12 fait échouer un job de CI, la cause la plus probable est un script qui appelle encore pnpm install --resolution-only. La v12 rejette cette option. Son rôle de signalement des peer dependencies revient désormais à pnpm peers check :
# pnpm 11
pnpm install --resolution-only
# pnpm 12
pnpm peers check
La v12 rejette également pnpm install --frozen-lockfile false. Utilisez --no-frozen-lockfile pour désactiver le mode frozen-lockfile, et simplement --frozen-lockfile pour l’activer.
Les autres changements affectent surtout les résultats, mais trois d’entre eux peuvent aussi interrompre une commande :
| Changement | Qui est concerné | Que faire |
|---|---|---|
| Les dépendances Git hébergées sur GitHub/GitLab/Bitbucket sont résolues via HTTPS | Dépôts privés accessibles en SSH | Configurer la réécriture d’URL Git sur la machine |
Les clés inconnues de pnpm-workspace.yaml sont signalées, et font échouer la commande avec ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS lorsque le projet épingle une version de pnpm que le pnpm en cours d’exécution satisfait | Configurations comportant des fautes de frappe | Corriger ou supprimer la clé |
Les commandes qui modifient l’installation globale échouent sous sudo avec ERR_PNPM_SUDO_NOT_SUPPORTED | sudo pnpm self-update et commandes similaires | Les exécuter sans sudo |
Avec engineStrict activé, un moteur incompatible dans les dependencies classiques fait échouer l’installation, même s’il figure aussi dans optionalDependencies | Projets utilisant engineStrict | S’attendre à ce que des installations qui émettaient un avertissement échouent désormais |
Sous Linux, packageImportMethod: auto tente les liens physiques avant les reflinks | Utilisateurs Linux | Généralement rien |
Les node, deno ou bun globaux suivent la version épinglée par le projet | Machines disposant de runtimes globaux | S’attendre à la version épinglée |
Les notes de version de la v12.0.0 expliquent l’importance de la vérification du workspace. Dans pnpm 11, une faute de frappe dans un paramètre comme minimumReleaseAge faisait que pnpm ignorait silencieusement la clé, si bien que la règle qu’elle devait définir ne s’appliquait jamais :
# pnpm-workspace.yaml
packages:
- "apps/*"
minimumReleseAge: # typo: pnpm 12 reports this key
Le guide de compatibilité recense huit différences au total. Six modifient un résultat, et deux rejettent une syntaxe de ligne de commande que pnpm 11 acceptait : --resolution-only et --frozen-lockfile false. Le tableau ci-dessus ne les couvre pas toutes. Il omet notamment la façon dont pnpm 12 traite les noms de gestionnaires de paquets comme yarn dans pnpm add, et les lignes concernant les clés du workspace et sudo proviennent des notes de version plutôt que du guide. Lisez le guide complet avant de procéder à la mise à niveau.
Faut-il passer à pnpm 12 ?
En général, oui, et la mise à niveau se déroule sans encombre : c’était l’objectif de conception. À partir de pnpm 11.10 ou d’une version ultérieure, exécutez :
pnpm self-update
Dans un projet qui épingle pnpm via packageManager, self-update se contente de mettre à jour la version dans ce champ au lieu d’installer pnpm globalement. pnpm récupère ensuite la nouvelle version à la prochaine exécution d’une commande. Commitez la modification pour que la CI utilise la même version :
{
"packageManager": "pnpm@12.8.1"
}
Utilisez la dernière version 12.x. Si votre installation repose sur des fonctionnalités moins courantes, comme pnpm deploy ou certains modes de linker spécifiques, testez d’abord la mise à niveau sur une branche. Les équipes encore sous npm peuvent consulter cet article pour savoir si passer de npm à pnpm est pertinent avant d’engager les deux changements à la fois.
Conclusion
pnpm 12 a conservé ce que vous utilisez au quotidien, notamment les commandes, le format du lockfile et le modèle de store, et a reconstruit le moteur qui se trouve derrière. La réécriture a porté ses fruits parce que deux coûts limitaient la version JavaScript : le démarrage de Node.js à chaque invocation et les entrées/sorties fichiers canalisées par un unique runtime. Avant de migrer, recherchez --resolution-only et --frozen-lockfile false dans votre configuration de CI, vérifiez la présence de dépendances Git privées accessibles en SSH, et commitez séparément le premier lockfile issu d’une nouvelle résolution afin de pouvoir en examiner le diff.
FAQ
pnpm 12 a-t-il besoin de Node.js pour fonctionner ?
Non. Une fois installé, pnpm 12 s'exécute comme un programme natif : Node.js n'est donc pas nécessaire. Le script d'installation autonome n'a pas non plus besoin de Node.js, même au moment de l'installation. La seule exception concerne l'installation de pnpm 12 via npm, où l'installeur requiert Node.js 22.13 ou une version ultérieure. Si aucun binaire précompilé de pnpm 12 n'existe pour votre plateforme, la documentation de pnpm recommande d'utiliser plutôt pnpm 11, écrit en JavaScript.
Comment continuer à utiliser SSH pour les dépendances Git privées avec pnpm 12 ?
pnpm 12 récupère les dépendances GitHub, GitLab et Bitbucket via l'URL HTTPS de chaque hébergeur. Pour continuer à utiliser SSH, configurez une réécriture d'URL Git, par exemple avec git config --global url.'git@github.com:'.insteadOf https://github.com/. pnpm appelle git en coulisses, si bien que cette règle s'applique à toutes les commandes Git exécutées par pnpm. Les hébergeurs que pnpm ne reconnaît pas, ainsi que les URL contenant des identifiants, sont conservés exactement tels que vous les avez écrits, SSH compris.
Pourquoi pnpm 12 échoue-t-il sur un paramètre de pnpm-workspace.yaml non reconnu ?
L'échec ne se produit que lorsque le projet épingle une version de pnpm et que le pnpm en cours d'exécution correspond à cette version. Dans ce cas, pnpm considère la clé inconnue comme une erreur et s'arrête avec ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS. En l'absence d'épinglage correspondant, vous obtenez un avertissement et la commande se poursuit. Si la clé ressemble à une faute de frappe, pnpm indique le paramètre que vous vouliez probablement utiliser. Les commandes pnpm config fonctionnent toujours sur un fichier contenant une clé erronée : vous pouvez donc vous en servir pour la repérer et la corriger.
Quelles commandes pnpm 12 échouent lorsqu'elles sont exécutées avec sudo ?
Sous sudo, pnpm setup, pnpm self-update et toutes les commandes qui modifient l'installation globale, comme pnpm add --global, s'arrêtent avec ERR_PNPM_SUDO_NOT_SUPPORTED. Les versions précédentes écrivaient silencieusement dans le répertoire personnel de root. Les paquets et paramètres globaux résident dans votre propre répertoire personnel : aucune de ces commandes ne nécessite donc les droits root. Les commandes en lecture seule, comme pnpm bin --global, fonctionnent toujours sous sudo.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k