Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 117 minIntermédiaire

C'est quoi Node.js ? Définition, installation et premier script

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • expliquer ce qu'est Node.js et ce qui le distingue de JavaScript et d'Express ;
  • décrire le rôle de la boucle d'événements et du code non bloquant ;
  • choisir et installer une version LTS de Node.js ;
  • exécuter un script et lire un fichier avec node:fs/promises.

5 exercices corrigés1 schéma

Node.js est un environnement d'exécution JavaScript : un programme qui fait tourner du JavaScript hors du navigateur, directement sur un ordinateur ou un serveur. Il sert surtout à écrire des serveurs web et des API, mais aussi des outils en ligne de commande et des scripts. Ce chapitre explique ce qu'est Node.js, pourquoi il gère très bien beaucoup de requêtes à la fois, quelle version installer, puis te fait écrire tes premiers scripts.

Node.js, JavaScript et Express : qui fait quoi

Trois mots reviennent sans cesse, et les confondre fait perdre des points à l'oral.

TermeCe que c'estAnalogie
JavaScriptUn langage de programmation, normalisé sous le nom ECMAScriptLa langue dans laquelle tu écris
Node.jsUn environnement d'exécution (runtime) : le moteur V8 de Chrome, plus des modules pour accéder aux fichiers, au réseau, aux processusL'interprète qui lit ta langue et agit sur la machine
ExpressUn framework web écrit pour Node.js : routes, middlewares, réponses HTTPUn manuel de procédures qui t'évite de tout réinventer

Node.js n'est donc ni un langage ni un framework. Tu écris du JavaScript ; Node.js l'exécute ; Express t'aide à structurer un serveur web. Un navigateur est aussi un environnement d'exécution JavaScript, mais il offre d'autres objets : document et window existent dans le navigateur et pas dans Node.js ; à l'inverse, Node.js donne accès au disque (node:fs), aux processus (process) et au réseau bas niveau (node:net), interdits à une page web.

Node.js a été créé en 2009 par Ryan Dahl. Il est libre (licence MIT) et piloté par l'OpenJS Foundation. Il est installé avec npm, le gestionnaire de paquets qui donne accès à des millions de bibliothèques (chapitre 2).

À quoi sert Node.js

  • Des API et des back-ends web : c'est l'usage de ce cours. Le front (React, une application mobile) envoie des requêtes HTTP ; l'API Node.js répond en JSON.
  • Du temps réel : messagerie, notifications, tableaux de bord mis à jour en direct (WebSocket).
  • Des outils de développement : Vite, ESLint, Prettier, TypeScript et le serveur de développement de React tournent tous sous Node.js. Même si tu ne codes pas de back-end en JavaScript, tu utilises Node.js dès que tu fais du front moderne.
  • Des scripts : traiter un fichier CSV, appeler une API la nuit, générer un rapport.

Node.js est moins adapté aux calculs lourds qui monopolisent le processeur (traitement d'image, calcul scientifique) : la section sur la boucle d'événements explique pourquoi.

CritèrePHP (avec PHP-FPM)Node.js
Qui démarre le programmeLe serveur web lance un script PHP pour chaque requêteTon programme démarre une fois et reste en mémoire
Requêtes simultanéesPlusieurs processus PHP, un par requête en coursUn seul processus qui alterne entre les requêtes pendant les attentes
Serveur HTTPApache ou Nginx devant PHPIntégré : ton code écoute lui-même un port
Langage du front et du backDeux langagesLe même JavaScript partout

Aucune des deux approches n'est « meilleure » : PHP est simple à héberger et omniprésent, Node.js brille quand l'application passe son temps à attendre la base de données ou d'autres services, ce qui est le cas de la plupart des API.

Le moteur V8 et la boucle d'événements

Node.js exécute ton JavaScript avec V8, le moteur de Google Chrome, qui compile le code en langage machine à la volée. Ton code tourne sur un seul fil d'exécution (thread) : une seule instruction JavaScript s'exécute à un instant donné.

Comment un seul fil peut-il servir des centaines de requêtes ? Parce qu'une API passe l'essentiel de son temps à attendre : la réponse de MySQL, la lecture d'un fichier, la réponse d'un autre service. Node.js ne reste pas les bras croisés pendant ces attentes. Il confie l'opération au système d'exploitation (ou à un petit groupe de fils internes, géré par la bibliothèque libuv), passe à la requête suivante, et reprend le traitement quand le résultat arrive. C'est le modèle asynchrone non bloquant, orchestré par la boucle d'événements (event loop).

Pile d'appelston JavaScript, un seul fillireFiche()trouverParId()pool.execute()une instruction à la foislanceSystème et libuvrequête MySQLlecture de fichierappel réseau, minuteuren parallèle, hors du filfiniFiles d'attenteles suites à exécuter1. microtâchespromesses résolues2. tâchesminuteurs, E/Sboucle d'événementsdès que la pile est vide, elle exécute la prochaine suite, microtâches d'abordune API attend surtout :la base, le disque, le réseau
Un seul fil pour ton code, les attentes confiées au système, les suites exécutées dès que la pile est libre

Voici ce que ça change concrètement. Ce script affiche quatre lignes ; devine l'ordre avant de lire le résultat.

js
console.log('1. début du script');
setTimeout(() => console.log('4. minuteur à 0 ms'), 0);
Promise.resolve().then(() => console.log('3. promesse résolue'));
console.log('2. fin du script');
text
1. début du script
2. fin du script
3. promesse résolue
4. minuteur à 0 ms

Le code synchrone s'exécute d'abord, jusqu'au bout. Ensuite seulement, la boucle traite ce qui attend : d'abord les suites de promesses (les microtâches), puis les minuteurs. Un setTimeout(…, 0) ne veut pas dire « tout de suite », mais « dès que possible, quand la pile est vide ».

Ne bloque jamais la boucle

Puisqu'il n'y a qu'un fil pour ton code, une instruction qui l'occupe longtemps bloque toutes les requêtes en même temps. Avec PHP, un script lent ne pénalise que son propre visiteur ; avec Node.js, il fige tout le serveur.

js
// À NE PAS FAIRE dans une route : 3 secondes de calcul pendant lesquelles
// aucune autre requête n'est servie, même /sante
const fin = Date.now() + 3000;
while (Date.now() < fin) { /* le processeur tourne à vide */ }

Les causes classiques, et leur remède :

Ce qui bloqueLe remède
Une fonction synchrone d'E/S dans une route : readFileSync, execSyncLa version asynchrone : await readFile(…) de node:fs/promises
Un hachage de mot de passe synchrone (bcrypt.hashSync)La version asynchrone (await argon2.hash(…), await bcrypt.hash(…))
Une boucle sur des centaines de milliers de lignesFaire le travail dans la base (WHERE, GROUP BY), paginer
Un vrai calcul lourd (image, PDF, chiffrement de gros fichiers)Un worker (node:worker_threads) ou un service séparé

Les fonctions …Sync ne sont pas interdites partout : dans un script lancé à la main, ou au démarrage du serveur avant qu'il n'accepte des requêtes, elles sont acceptables. Dans le traitement d'une requête, jamais.

Quelle version de Node.js choisir ?

Une nouvelle version majeure de Node.js sort tous les six mois. Les versions paires deviennent LTS (Long Term Support) en octobre : elles reçoivent ensuite des correctifs pendant deux ans et demi environ. Les versions impaires restent « Current » quelques mois puis s'arrêtent. Pour un projet, prends toujours une LTS.

VersionNom de codeLTS depuisPhase au 2 novembre 2026Fin de maintenance
Node.js 22Jodoctobre 2024Maintenance (correctifs de sécurité)30 avril 2027
Node.js 24Kryptonoctobre 2025Maintenance depuis le 20 octobre 202630 avril 2028
Node.js 26Lithium28 octobre 2026LTS active30 avril 2029

Le calendrier officiel du projet change à partir de Node.js 27, prévu en avril 2027 : une seule version majeure par an, qui deviendra LTS à l'automne suivant. Vérifie toujours la page des versions sur nodejs.org avant de démarrer un projet.

Installer Node.js

Trois façons de l'installer :

  • L'installeur officiel (nodejs.org, bouton LTS) : le plus simple sous Windows et macOS. Il installe node et npm.
  • Un gestionnaire de versions : nvm (Linux, macOS), nvm-windows ou fnm (tous systèmes). Il permet d'avoir plusieurs versions et d'en changer par projet. C'est le choix des développeurs qui jonglent entre plusieurs projets.
  • Un conteneur Docker (node:24-slim) : la même version pour toute l'équipe, sans rien installer sur le poste (chapitre 14).
bash
# Avec nvm : installer la LTS 24 et l'utiliser
nvm install 24
nvm use 24

# Vérifier
node --version     # v24.15.0 (le dernier chiffre change avec les correctifs)
npm --version      # 11.12.1

Sous Linux, évite le paquet nodejs des dépôts de ta distribution s'il est ancien : prends nvm ou le dépôt officiel de NodeSource.

Premier script et REPL

Crée un fichier bonjour.js :

js
const prenom = process.argv[2] ?? 'inconnu';
console.log(`Bonjour ${prenom}, Node.js ${process.version} tourne sur ${process.platform}.`);
bash
node bonjour.js Lucas
text
Bonjour Lucas, Node.js v24.15.0 tourne sur darwin.

process est un objet global de Node.js : process.argv contient les arguments de la ligne de commande (argv[0] est le chemin de node, argv[1] celui du script, puis tes arguments), process.env les variables d'environnement, process.exitCode le code de retour du programme. process.platform vaut win32 sous Windows, linux sous Linux, darwin sous macOS.

Lancé sans fichier, node ouvre le REPL (Read-Eval-Print Loop), une console où tu tapes du JavaScript et lis le résultat immédiatement. Pratique pour tester une méthode de tableau ou une expression régulière. .exit (ou deux fois Ctrl+C) pour en sortir.

Lire un fichier avec node:fs/promises

Les modules intégrés à Node.js s'importent avec le préfixe node:. Ce script lit le fichier tarifs.json placé à côté de lui et affiche les forfaits de frais d'AppliFrais :

json
[
  { "code": "ETP", "libelle": "Forfait étape", "montant": 110 },
  { "code": "KM", "libelle": "Frais kilométriques", "montant": 0.62 },
  { "code": "NUI", "libelle": "Nuitée hôtel", "montant": 80 },
  { "code": "REP", "libelle": "Repas restaurant", "montant": 25 }
]
js
// tarifs.js
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';

const chemin = join(import.meta.dirname, 'tarifs.json');

try {
  const texte = await readFile(chemin, 'utf8');
  const tarifs = JSON.parse(texte);
  for (const { code, libelle, montant } of tarifs) {
    console.log(`${code.padEnd(4)}${libelle.padEnd(22)}${montant.toFixed(2).padStart(7)} €`);
  }
} catch (erreur) {
  if (erreur.code === 'ENOENT') {
    console.error(`Fichier introuvable : ${chemin}`);
    process.exitCode = 1;
  } else {
    throw erreur;
  }
}
text
ETP Forfait étape          110.00 €
KM  Frais kilométriques      0.62 €
NUI Nuitée hôtel            80.00 €
REP Repas restaurant        25.00 €

Quatre détails à retenir :

  • ce fichier utilise import : le projet doit être en modules ES, avec "type": "module" dans le package.json (chapitre 2). Avec "type": "commonjs", la valeur que npm init écrit par défaut, Node.js s'arrête sur SyntaxError: Cannot use import statement outside a module ; sans champ type, il relit le fichier comme module ES et affiche un avertissement ;
  • await est permis directement au niveau du module (top-level await), sans fonction async autour ;
  • import.meta.dirname est le dossier du fichier en cours. Sans lui, un chemin relatif comme 'tarifs.json' est résolu depuis le dossier où tu as lancé la commande, pas depuis celui du script : une source d'erreurs fréquente ;
  • une erreur système porte un code lisible : ENOENT (fichier absent), EACCES (droits insuffisants), EADDRINUSE (port déjà utilisé), ECONNREFUSED (service injoignable, souvent MySQL arrêté). Teste erreur.code plutôt que le texte du message.

Les modules intégrés à connaître

ModuleSert àExemple
node:fs/promisesLire et écrire des fichiers et des dossiersawait writeFile('export.csv', texte)
node:pathConstruire des chemins valables sous Windows comme sous Linuxjoin(import.meta.dirname, 'stockage')
node:cryptoIdentifiants aléatoires, hachage, chiffrementrandomUUID()
node:httpCréer un serveur HTTP (Express s'appuie dessus)createServer(…)
node:test et node:assertÉcrire et lancer des tests (chapitre 12)assert.equal(total, 898.9)
node:osInformations sur la machineos.cpus().length

Certaines fonctions sont globales et n'ont pas besoin d'import : console, process, setTimeout, structuredClone, et surtout fetch, le même que dans le navigateur, pour appeler une autre API depuis ton serveur.

Exercices

Exercice 1 sur 5 L'ordre d'affichage Réussi À revoir

Dans quel ordre ce script affiche-t-il les lettres ? Justifie.

js
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
queueMicrotask(() => console.log('D'));
console.log('E');
Voir la réponseMasquer la réponse de l'exercice 1

A, E, C, D, B.

Le code synchrone s'exécute d'abord jusqu'au bout : A puis E. Quand la pile d'appels est vide, Node.js traite toutes les microtâches, dans l'ordre où elles ont été mises en file : la suite de la promesse (C), puis la fonction passée à queueMicrotask (D). Les minuteurs ne passent qu'ensuite : B, même avec un délai de 0 ms.

Tu avais trouvé ?

Exercice 2 sur 5 Langage, environnement ou framework ? Réussi À revoir

Classe chaque élément : JavaScript, Node.js, Express, V8, npm, React. Puis corrige la phrase d'un camarade : « Mon back-end est codé en Node.js, qui est un framework JavaScript. »

Voir la réponseMasquer la réponse de l'exercice 2
  • JavaScript : un langage.
  • Node.js : un environnement d'exécution.
  • V8 : le moteur JavaScript de Chrome, utilisé par Node.js.
  • Express : un framework web pour Node.js.
  • npm : le gestionnaire de paquets fourni avec Node.js.
  • React : une bibliothèque d'interface, côté front.

Phrase corrigée : « Mon back-end est écrit en JavaScript, exécuté par Node.js, avec le framework Express. »

Tu avais trouvé ?

Exercice 3 sur 5 Bloquant ou pas ? Réussi À revoir

Pour chaque ligne placée dans une route d'API, dis si elle bloque la boucle d'événements, et propose une correction si c'est le cas.

  1. const texte = readFileSync('modele.html', 'utf8');
  2. const [lignes] = await pool.execute('SELECT * FROM fiche_frais WHERE id = ?', [id]);
  3. const hache = bcrypt.hashSync(motDePasse, 12);
  4. const reponse = await fetch('https://api.example/taux');
  5. Une boucle for qui additionne les montants de 200 000 lignes chargées en mémoire.
Voir la réponseMasquer la réponse de l'exercice 3
  1. Bloque : lecture synchrone. Utilise await readFile(…) de node:fs/promises, ou lis le fichier une seule fois au démarrage du serveur.
  2. Ne bloque pas : la requête part vers MySQL, Node.js sert d'autres requêtes en attendant la réponse.
  3. Bloque, et longtemps : un hachage de mot de passe est volontairement lent. Utilise la version asynchrone, await bcrypt.hash(motDePasse, 12), ou mieux await argon2.hash(motDePasse) (chapitre 9).
  4. Ne bloque pas : appel réseau asynchrone.
  5. Bloque pendant toute la boucle, et charger 200 000 lignes en mémoire est déjà une erreur. Fais faire le calcul à la base : SELECT SUM(montant) FROM ….

Tu avais trouvé ?

Exercice 4 sur 5 Choisir une version Réussi À revoir

Le 2 novembre 2026, ton équipe démarre la réalisation qu'elle présentera à l'E6 en mai 2027. Un camarade propose Node.js 25 « parce que c'est la plus récente après la 26 ». Que lui réponds-tu ? Quelle version choisis-tu, et où l'écris-tu ?

Voir la réponseMasquer la réponse de l'exercice 4

Node.js 25 est une version impaire : elle n'est jamais LTS et n'est plus maintenue. Il faut une LTS : Node.js 26 (LTS active depuis le 28 octobre 2026, maintenue jusqu'en avril 2029) ou Node.js 24 (maintenue jusqu'en avril 2028), toutes deux couvertes jusqu'à l'épreuve. L'important est de choisir une version et de l'écrire partout : champ engines du package.json, image du Dockerfile (node:24-slim ou node:26-slim), version du pipeline de CI, et fiche descriptive de la réalisation.

Tu avais trouvé ?

Exercice 5 sur 5 Un script utile Réussi À revoir

Écris un script total.js qui lit tarifs.json (le fichier de ce chapitre) et affiche le montant des frais forfaitisés d'une fiche de 3 étapes, 420 km, 2 nuitées et 5 repas. Le résultat attendu est 875.40 €.

Voir la réponseMasquer la réponse de l'exercice 5
js
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';

const tarifs = JSON.parse(await readFile(join(import.meta.dirname, 'tarifs.json'), 'utf8'));
const quantites = { ETP: 3, KM: 420, NUI: 2, REP: 5 };

let centimes = 0;
for (const { code, montant } of tarifs) {
  centimes += quantites[code] * Math.round(montant * 100);
}
console.log(`${(centimes / 100).toFixed(2)} €`);

3 × 110 + 420 × 0,62 + 2 × 80 + 5 × 25 = 330 + 260,40 + 160 + 125 = 875,40 €. Le calcul se fait en centimes : en virgule flottante, certains produits tombent faux, par exemple 57 * 0.62 donne 35.339999999999996 et 3 * 0.62 donne 1.8599999999999999. Pour de l'argent, compte en entiers, puis divise par 100 à l'affichage.

Tu avais trouvé ?

Chapitre terminé !

Fais les 5 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : npm, package.json et modules ES (import, export)Revoir le sommaire du cours