Les projets Node.js ont souvent des centaines de dépendances. Sans cache,
chaque npm ci télécharge tout depuis le registre npm, 30 à 60 secondes
minimum. Avec le cache, c'est réduit à quelques secondes.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Activer le cache intégré de
setup-nodepour npm, pnpm et yarn - Configurer
actions/cachequand vous avez besoin de contrôle - Cacher les builds Next.js, Turborepo et ESLint
- Gérer un monorepo à workspaces
- Éviter les pièges du cache de
node_moduleset de pnpm
Cache intégré avec setup-node
Section intitulée « Cache intégré avec setup-node »L'action setup-node sait gérer le cache elle-même : une ligne suffit, elle
calcule la clé à partir du lockfile et restaure le cache du gestionnaire
de paquets avant l'installation. Attention à ce qui est réellement mis en
cache : le magasin de téléchargement (~/.npm), pas node_modules. npm ci
s'exécute donc toujours, mais sans aucun appel réseau au registre, ce qui
concentre le gain.
La méthode la plus simple :
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'npm' # Détecte automatiquement package-lock.json
- run: npm ciDétection automatique du gestionnaire
Section intitulée « Détection automatique du gestionnaire »setup-node détecte le gestionnaire de paquets selon les fichiers présents,
mais la valeur de cache: reste à votre charge : elle doit correspondre au
lockfile versionné dans le dépôt. Une valeur npm sur un projet qui n'a
qu'un pnpm-lock.yaml fait échouer le step, faute de fichier à hacher.
| Fichier présent | Gestionnaire détecté |
|---|---|
package-lock.json | npm |
pnpm-lock.yaml | pnpm |
yarn.lock | yarn |
# Pour pnpm- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'pnpm'
- run: pnpm install
# Pour yarn- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'yarn'
- run: yarn install --frozen-lockfileCache manuel
Section intitulée « Cache manuel »Pour plus de contrôle ou des cas spécifiques, actions/cache reprend la main :
vous choisissez le chemin à conserver, la clé exacte et les
restore-keys de repli. C'est indispensable quand vous devez cacher autre chose
que le magasin du gestionnaire de paquets, ou partager un cache entre plusieurs
jobs qui n'appellent pas setup-node.
Cache npm
Section intitulée « Cache npm »Le chemin du magasin npm varie selon le système et la version : le lire avec
npm config get cache évite de le coder en dur et garde le workflow valable sur
ubuntu, macos et windows. Les restore-keys servent de repli quand le
lockfile a changé, le cache le plus proche est alors réutilisé plutôt que
reparti de zéro.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20'
- name: Get npm cache directory id: npm-cache-dir shell: bash run: echo "dir=$(npm config get cache)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ${{ steps.npm-cache-dir.outputs.dir }} key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} restore-keys: | npm-${{ runner.os }}-
- run: npm ciCache pnpm
Section intitulée « Cache pnpm »L'ordre des deux actions n'est pas interchangeable : setup-node interroge
pnpm store path pour savoir quoi cacher, donc pnpm doit déjà être installé
au moment où il s'exécute.
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 with: version: 9
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'pnpm'
- run: pnpm install --frozen-lockfileCache yarn (v3+)
Section intitulée « Cache yarn (v3+) »Sur Yarn Berry, --immutable remplace l'ancien --frozen-lockfile et fait
échouer l'installation si le yarn.lock devait être modifié, exactement ce
qu'on attend en CI.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'yarn'
- run: yarn install --immutableCache du node_modules
Section intitulée « Cache du node_modules »Pour des gains maximum, cachez directement node_modules : sur un cache
hit, l'installation est purement et simplement sautée, ce qui supprime les
quelques secondes que npm ci passe encore à écrire l'arborescence. La
condition if: sur la sortie cache-hit est ce qui rend l'approche viable :
sans elle, vous restaureriez le cache puis réinstalleriez par-dessus.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20'
- name: Cache node_modules uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 id: cache-node-modules with: path: node_modules key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
- name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' run: npm ciCache des builds
Section intitulée « Cache des builds »Au-delà des dépendances, les outils de build maintiennent leur propre cache sur disque. Le préserver d'un run à l'autre accélère franchement la compilation.
Cache Next.js
Section intitulée « Cache Next.js »Next.js conserve dans .next/cache les modules déjà compilés et les images
optimisées. La clé combine ici le lockfile et le hash des sources : elle
change à chaque modification de code, et les restore-keys fournissent alors le
cache précédent comme point de départ, ce qui limite la recompilation aux
fichiers modifiés.
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | .next/cache key: nextjs-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} restore-keys: | nextjs-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}- nextjs-${{ runner.os }}-Cache Turborepo
Section intitulée « Cache Turborepo »Turborepo indexe le résultat de chaque tâche dans .turbo et le rejoue tel quel
si les entrées n'ont pas bougé : sur un monorepo, seuls les packages
modifiés sont reconstruits. Le github.sha dans la clé garantit une écriture
à chaque run, les restore-keys assurant la reprise du cache le plus récent.
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .turbo key: turbo-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ github.sha }} restore-keys: | turbo-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}- turbo-${{ runner.os }}-Cache ESLint
Section intitulée « Cache ESLint »Le fichier .eslintcache mémorise l'empreinte des fichiers déjà analysés sans
erreur ; le drapeau --cache est obligatoire côté commande, sinon rien n'est ni
lu ni écrit. Sur un gros dépôt, le lint ne porte alors plus que sur les fichiers
modifiés.
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .eslintcache key: eslint-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
- run: npm run lint -- --cacheWorkflow complet
Section intitulée « Workflow complet »Ce workflow assemble les briques précédentes dans un cas réel : test d'une
bibliothèque sur trois versions de Node. La matrice lance trois jobs
indépendants, et comme runner.os et la version de Node entrent dans la clé
calculée par setup-node, chacun dispose de son cache propre sans écraser
celui des autres.
name: Node.js CI
on: push: branches: [main] pull_request: branches: [main]
# Aucun droit par défaut : le job demande le minimumpermissions: {}
jobs: build: runs-on: ubuntu-24.04 permissions: contents: read
strategy: matrix: node-version: [18, 20, 22]
steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false
- name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ matrix.node-version }} cache: 'npm'
- name: Install dependencies run: npm ci
- name: Lint run: npm run lint
- name: Test run: npm test
- name: Build run: npm run buildMonorepo avec workspaces
Section intitulée « Monorepo avec workspaces »Dans un monorepo, setup-node ne regarde par défaut que le lockfile à la
racine : une modification dans un package ne change alors pas la clé, et le
cache restauré est périmé. cache-dependency-path corrige ce comportement en
faisant entrer tous les lockfiles du dépôt dans le calcul de la clé.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'npm' cache-dependency-path: '**/package-lock.json' # Tous les lockfiles
- run: npm ci --workspacesAvec pnpm workspaces
Section intitulée « Avec pnpm workspaces »pnpm n'a pas besoin de ce réglage : son lockfile unique à la racine décrit
déjà tous les packages du workspace. L'option -r exécute ensuite le script
dans chaque package, en respectant l'ordre de leurs dépendances internes.
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 with: version: 9
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '20' cache: 'pnpm'
- run: pnpm install --frozen-lockfile- run: pnpm -r build # Build tous les packagesOptimisations avancées
Section intitulée « Optimisations avancées »Certains cas particuliers, modules natifs, tests end-to-end, ont leurs propres caches à connaître.
Packages natifs (node-gyp)
Section intitulée « Packages natifs (node-gyp) »Pour les packages avec compilation native (sharp, bcrypt, etc.), le coût n'est
pas le téléchargement mais la compilation. node-gyp télécharge en plus les
en-têtes du noyau Node dans ~/.node-gyp : les cacher évite de les récupérer à
chaque run. La version de Node entre ici dans la clé, un binaire compilé pour
Node 20 étant inutilisable sur Node 22.
- name: Cache native modules uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.npm ~/.node-gyp key: native-${{ runner.os }}-node${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}Cypress installe son navigateur, plusieurs centaines de mégaoctets, hors de
node_modules, dans ~/.cache/Cypress : ce dossier échappe donc au cache npm
et se déclare séparément.
- name: Cache Cypress uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.cache/Cypress key: cypress-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}Erreurs courantes
Section intitulée « Erreurs courantes »Deux problèmes reviennent souvent avec le cache Node.js. Voici comment les reconnaître et les corriger.
Cache invalide sur npm ci
Section intitulée « Cache invalide sur npm ci »Ce message ne vient pas du cache lui-même mais d'un package.json et d'un
package-lock.json désynchronisés. Une clé de cache qui ignore le lockfile
prolonge le problème : le workflow restaure indéfiniment un magasin obsolète et
l'erreur survit aux relances.
npm ERR! `npm ci` can only install packages when your package.json and package-lock.json are in syncLa clé de cache doit inclure le hash du lockfile :
# ✅ Correctkey: npm-${{ hashFiles('**/package-lock.json') }}pnpm : store non trouvé
Section intitulée « pnpm : store non trouvé »Le symptôme est un step setup-node qui échoue en annonçant ne pas trouver le
store pnpm. La cause est toujours la même : setup-node s'exécute avant
l'installation de pnpm et n'a donc aucune commande à interroger pour localiser
le magasin.
# Assurez-vous d'installer pnpm avant setup-node- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: cache: 'pnpm'Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Le cache intégré de
setup-node(cache: 'npm'/'pnpm'/'yarn') couvre la majorité des projets. - Pour pnpm, installez
pnpm/action-setupavantsetup-node, sinon le store reste introuvable. - Cacher
node_modulesdirectement est plus rapide mais fragile : les scriptspostinstallsont sautés sur un cache hit. - Cachez les builds (
.next/cache,.turbo,.eslintcache) en plus des dépendances pour le gain maximal. - En monorepo,
cache-dependency-path: '**/package-lock.json'couvre tous les workspaces.