À mesure que ton bot grandit, Discord finira par t'envoyer cet avertissement : le bot a rejoint trop de serveurs et une seule connexion (shard) ne suffit plus. C'est précisément là qu'intervient le Discord sharding. Discord autorise un bot à gérer au maximum 2500 serveurs par connexion gateway ; une fois cette limite franchie, diviser le bot en plusieurs shards devient obligatoire. Dans ce guide, j'explique pas à pas ce qu'est le sharding, comment faire évoluer ton bot avec la classe ShardingManager de discord.js, et les subtilités de l'agrégation de données entre shards.
Qu'est-ce que le sharding et quand en a-t-on besoin ?
Un shard est une unique connexion WebSocket que ton bot ouvre vers le gateway de Discord. Chaque shard est responsable d'un sous-ensemble de serveurs et ne reçoit les événements (messages, mises à jour de membres, état vocal) que pour ses propres serveurs. Discord répartit les serveurs entre les shards avec cette formule :
shard_id = (guild_id >> 22) % nombre_total_de_shards
Ainsi, le shard sur lequel atterrit un serveur dépend de son ID — ce n'est pas aléatoire. Le moment où le sharding devient nécessaire est clair :
- Limite stricte : au-delà de 2500 serveurs, Discord ne te laisse plus te connecter avec un seul shard.
- Performance : même en dessous de 2500, un seul processus Node.js peut peiner à supporter le trafic d'événements et le cache de milliers de serveurs ; le sharding répartit la charge.
- Résilience : si un shard plante, les autres continuent de tourner.
Un point important : pour de petits bots bien en dessous de 2500, le sharding est une complexité inutile. N'optimise pas trop tôt ; l'ajouter avant le besoin ne fait que compliquer le développement.
Démarrer avec ShardingManager
discord.js fournit une classe ShardingManager prête à l'emploi qui gère le sharding à ta place. L'idée est la suivante : au lieu d'exécuter directement le fichier principal de ton bot (par exemple bot.js), tu écris un script gestionnaire (manager.js). Ce gestionnaire lance ton bot sous forme de plusieurs processus séparés, chacun étant un shard.
D'abord, le fichier gestionnaire :
// manager.js
const { ShardingManager } = require('discord.js');
require('dotenv').config();
const manager = new ShardingManager('./bot.js', {
token: process.env.DISCORD_TOKEN,
totalShards: 'auto',
});
manager.on('shardCreate', shard => {
console.log(`Shard ${shard.id} lancé`);
});
manager.spawn();
Le réglage totalShards: 'auto' fait que discord.js demande à Discord le nombre de shards recommandé et lance le bon nombre de processus. Tu peux aussi le passer manuellement (totalShards: 4), mais 'auto' est le choix le plus sûr dans la plupart des cas.
Ton fichier bot proprement dit change à peine :
// bot.js
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [GatewayIntentBits.Guilds],
});
client.once('ready', () => {
console.log(`Connecté : ${client.user.tag} | Shard : ${client.shard.ids}`);
});
client.login(process.env.DISCORD_TOKEN);
Remarque : dans bot.js, tu passes toujours le token à client.login, mais tu ne lui dis jamais quel shard il est. Le ShardingManager transmet les identifiants de shard via les variables d'environnement au lancement de chaque processus, et discord.js les lit automatiquement. Désormais, tu démarres le bot avec node manager.js, et non node bot.js.
Agréger les données entre shards : broadcastEval
La partie la plus déroutante du sharding est celle-ci : puisque chaque shard est un processus séparé, il possède son propre client.guilds.cache et ne peut pas voir les serveurs des autres shards. Si tu veux connaître le nombre total de serveurs du bot, regarder un seul shard est trompeur. Tu dois exécuter le même code sur chaque shard et combiner les résultats. discord.js le fait avec broadcastEval :
// Dans un gestionnaire de commande
const resultats = await client.shard.broadcastEval(c => c.guilds.cache.size);
const totalServeurs = resultats.reduce((somme, valeur) => somme + valeur, 0);
console.log(`Total des serveurs : ${totalServeurs}`);
broadcastEval exécute la fonction que tu lui donnes dans le processus de chaque shard et renvoie un tableau de résultats, un élément par shard. Tu les fusionnes ensuite avec reduce. Le même schéma s'applique au nombre total d'utilisateurs :
const resultatsMembres = await client.shard.broadcastEval(
c => c.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0)
);
const totalMembres = resultatsMembres.reduce((a, b) => a + b, 0);
Il y a ici une règle essentielle : la fonction passée à broadcastEval ne peut pas accéder directement aux variables extérieures, car elle s'exécute dans un autre processus. Pour transmettre des valeurs externes, tu utilises context :
const guildId = '123456789012345678';
const noms = await client.shard.broadcastEval(
(c, { idCible }) => {
const guild = c.guilds.cache.get(idCible);
return guild ? guild.name : null;
},
{ context: { idCible: guildId } }
);
const trouve = noms.find(nom => nom !== null);
Comme un serveur donné ne vit que sur un seul shard, la plupart des résultats renvoient null ; tu récupères celui qui est rempli avec find.
Mémoire, nombre de processus et hybrid sharding
Comme chaque shard est un processus Node.js distinct, l'utilisation de la RAM augmente proportionnellement au nombre de shards. 16 shards équivalent grosso modo à 16 instances de bot séparées. Sur de très gros bots (des dizaines de milliers de serveurs), cela peut épuiser la mémoire du serveur.
La solution est le hybrid sharding : regrouper plusieurs shards dans un seul processus (un cluster). Le ShardingManager intégré de discord.js ne le propose pas directement ; pour cela, on utilise le package communautaire discord-hybrid-sharding. Le principe : si tu répartis 32 shards en 4 clusters, seuls 4 processus sont lancés, chacun portant 8 shards. L'empreinte mémoire chute fortement. Les petits et moyens bots n'en ont pas besoin ; le ShardingManager standard suffit largement.
Quelques points pratiques pour planifier ton nombre de processus :
- Réduis le cache : n'active pas d'
intentset de caches inutiles ; chaque shard gardant son propre cache, le gaspillage a un effet multiplicateur. - Mode process ou worker :
ShardingManagerlance des processus séparés par défaut ; avecmode: 'worker'tu peux utiliser worker_threads, mais l'isolation est plus forte en mode process. - Redémarrage : avec l'option
respawnactivée, un shard qui plante se relance automatiquement.
Questions fréquentes
Dois-je sharder avant que mon bot atteigne 2500 serveurs ?
Non, ce n'est pas nécessaire. Discord te laisse te connecter avec un seul shard jusqu'à 2500 serveurs. Tant que tu n'approches pas cette limite, le sharding n'ajoute qu'une complexité et une consommation mémoire inutiles. Quand tu t'en approches, passer à ShardingManager ne représente que quelques fichiers — ne t'en occupe pas trop tôt.
Dois-je définir le nombre de shards manuellement ou utiliser 'auto' ?
Dans la plupart des cas, totalShards: 'auto' est le mieux ; discord.js demande le nombre recommandé par Discord et lance les processus en conséquence. N'envisage un nombre manuel que si tu as une stratégie de distribution particulière (par exemple répartir sur plusieurs machines).
Si un shard plante, tout le bot tombe-t-il ?
Non. Les shards sont des processus indépendants ; si l'un plante, les autres continuent. Seuls les serveurs de ce shard cessent temporairement de répondre. Avec respawn activé, le ShardingManager redémarre automatiquement le shard planté, ce qui rend la coupure brève.
Le moment est-il venu de faire évoluer ton bot ? Si tu as besoin d'aide pour construire une architecture de sharding, agréger des données avec broadcastEval ou passer au hybrid sharding, contacte-moi — emmenons ton bot à grande échelle ensemble.