Dans l’écosystème Node.js, npm et npx coexistent dans presque tous les projets front-end modernes. npm est le gestionnaire de paquets par défaut de Node.js, présent depuis les débuts de l’écosystème JavaScript. npx est arrivé plus tard, livré avec npm à partir de la version 5.2.0, pour répondre à un besoin précis : exécuter un outil ponctuel sans l’installer durablement dans le projet. Comprendre la frontière entre les deux change concrètement la façon dont on structure un workflow.
Ce que fait npm au quotidien dans un projet JavaScript
npm remplit deux rôles distincts qu’on a tendance à confondre. Le premier est la gestion des dépendances : installer, mettre à jour ou supprimer des paquets, qu’ils soient locaux au projet ou installés globalement sur la machine. Le second est l’exécution de scripts définis dans le fichier package.json.
Quand on lance npm install, npm résout le graphe de dépendances, télécharge les paquets et les inscrit dans le répertoire node_modules. Ces paquets font alors partie du projet : ils sont versionnés via package.json et package-lock.json, reproductibles sur toutes les machines de l’équipe.
La commande npm run permet d’exécuter les scripts personnalisés du projet. C’est le mécanisme standard pour lancer un build, démarrer un serveur de développement ou exécuter les tests. Ces scripts utilisent les binaires installés localement dans node_modules/.bin, ce qui garantit que toute l’équipe utilise la même version de chaque outil.
Quand npx entre en jeu : exécution sans installation permanente
npx répond à un cas précis : exécuter un outil CLI sans l’ajouter aux dépendances du projet. Si le paquet est déjà présent dans node_modules, npx l’utilise directement. S’il est absent, npx le télécharge dans le cache npm, l’exécute, puis ne le conserve pas dans le projet.
Ce comportement est particulièrement utile pour les outils d’initialisation. Lancer npx create-react-app mon-projet ou npx create-next-app permet de bootstrapper une application sans avoir installé ces générateurs globalement au préalable. L’outil est récupéré, utilisé une fois, et le projet repart propre.

Un autre usage fréquent concerne les outils de migration ou de codemods : on les exécute ponctuellement sur une base de code, sans justifier leur présence permanente dans les dépendances.
npm exec et les changements introduits depuis npm 7
Depuis npm 7, npx s’appuie sur npm exec. Ce n’est pas un détail d’implémentation sans conséquence : la gestion des options a changé, et une confirmation est désormais demandée avant d’installer un paquet absent du projet. Cette confirmation peut être contournée avec le flag -y ou --yes.
Pour les pipelines CI, la documentation recommande d’utiliser npm exec -- ... plutôt que npx directement. La double tiret (--) sépare explicitement les options transmises à npm de ceux transmis au programme exécuté, ce qui évite des ambiguïtés dans des environnements non interactifs.
Cette évolution rapproche les deux commandes sur le plan technique, mais leur usage reste sémantiquement différent : npm install pour ce qui appartient au projet, npx pour ce qu’on invoque sans appartenance.
Implications pour la chaîne d’approvisionnement dans un workflow front-end
Un point que les tutoriels de base n’abordent pas : npx peut exécuter du code absent des dépendances du projet. Le paquet est téléchargé depuis le registre npm au moment de l’exécution, sans passer par le processus de validation habituel d’une dépendance.
Cela a des implications concrètes dans un contexte d’équipe ou de CI. Un nom de paquet mal orthographié ou un paquet malveillant portant un nom proche d’un outil connu peut être exécuté sans que le projet n’en garde de trace dans ses fichiers de verrouillage. La documentation npm précise que le paquet téléchargé est placé dans le cache npm, pas dans node_modules.
Pour les workflows CI qui automatisent l’exécution d’outils via npx, il vaut mieux épingler une version explicite :
npx [email protected] --write .plutôt quenpx prettier --write .: la version est déterministe, le comportement est reproductible entre les exécutions.- Pour les outils exécutés régulièrement en CI, les installer comme dépendances de développement dans
package.jsonreste plus fiable que de les récupérer à chaque pipeline via npx. - La vérification du nom exact du paquet sur npmjs.com avant toute première exécution via npx limite le risque de typosquatting – une pratique documentée dans les registres de paquets publics.
npm vs npx : tableau de décision pour les cas courants
La distinction se résume souvent à une question de durée de vie. Un outil utilisé à chaque build mérite une place dans les dépendances gérées par npm. Un outil utilisé une seule fois, ou lors d’une initialisation, relève de npx.
| Situation | Commande recommandée |
|---|---|
| Installer une dépendance du projet (lodash, axios…) | npm install |
| Exécuter un script défini dans package.json | npm run |
| Bootstrapper une application (create-react-app, create-next-app) | npx |
| Lancer un codemod ou outil de migration ponctuel | npx |
| Exécuter un outil CLI en CI de façon répétée | npm install en devDependency + npm run |
| Tester rapidement un outil sans polluer le projet | npx |
La limite de npx pour les processus longs mérite d’être mentionnée : des outils comme des serveurs de développement ou des watchers exécutés via npx peuvent présenter des comportements moins prévisibles que leurs équivalents installés localement et lancés via npm run. Dans ce cas précis, les données disponibles ne permettent pas de quantifier l’impact, mais les retours de la communauté npm (notamment dans les issues du dépôt officiel) signalent ce comportement pour certains outils.
npm et npx ne sont pas en concurrence : ils opèrent à des niveaux différents du même workflow. La maîtrise des deux passe par la compréhension de ce que chaque commande inscrit ou non dans le projet – et par conséquent de ce qu’elle rend reproductible ou non pour l’ensemble de l’équipe.

