aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord Bots

Discord Sharding: Scaling Bots to Big Servers

As your bot grows, one day Discord will hand you a warning: the bot has joined too many servers and a single connection (shard) is no longer enough. This is exactly where Discord sharding comes in. Discord allows a bot to handle at most 2500 guilds per gateway connection; once you cross that limit, splitting the bot into multiple shards becomes mandatory. In this guide I'll walk through what sharding is, how to scale your bot with discord.js's ShardingManager class, and the subtleties of aggregating data across shards.

What is sharding and when do you need it?

A shard is a single WebSocket connection your bot opens to the Discord gateway. Each shard is responsible for a subset of guilds and only receives events (messages, member updates, voice state) for its own guilds. Discord distributes guilds across shards with this formula:

shard_id = (guild_id >> 22) % total_shard_count

So which guild lands on which shard is determined by the guild's ID — it isn't random. When you need sharding is clear:

  • Hard limit: Once the bot passes 2500 guilds, Discord won't let you connect with a single shard.
  • Performance: Even below 2500, a single Node.js process can struggle to carry the event traffic and cache of thousands of guilds; sharding spreads the load.
  • Resilience: If one shard crashes, the others keep running.

One important point: for small bots well below 2500, sharding is needless complexity. Don't optimize early; adding it before the need arises only makes development harder.

Getting started with ShardingManager

discord.js ships with a ready-made ShardingManager class that handles sharding for you. The idea is this: instead of running your bot's main file (say bot.js) directly, you write a manager script (manager.js). This manager launches your bot as multiple separate processes, each one a shard.

First, the manager file:

// 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(`Launched shard ${shard.id}`);
});

manager.spawn();

The totalShards: 'auto' setting makes discord.js ask Discord for the recommended shard count and spawn the right number of processes. You can also pass it manually (totalShards: 4), but 'auto' is the safest choice in most cases.

Your actual bot file barely changes:

// bot.js
const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
  intents: [GatewayIntentBits.Guilds],
});

client.once('ready', () => {
  console.log(`Logged in: ${client.user.tag} | Shard: ${client.shard.ids}`);
});

client.login(process.env.DISCORD_TOKEN);

Notice that in bot.js you still pass the token to client.login, but you never tell it which shard it is. The ShardingManager passes the shard IDs through environment variables when launching each process, and discord.js reads them automatically. From now on you start the bot with node manager.js, not node bot.js.

Aggregating data across shards: broadcastEval

The most confusing part of sharding is this: since each shard is a separate process, it has its own client.guilds.cache and cannot see the guilds on other shards. If you want to know the bot's total guild count, looking at a single shard is misleading. You need to run the same code on every shard and combine the results. discord.js does this with broadcastEval:

// Inside a command handler
const results = await client.shard.broadcastEval(c => c.guilds.cache.size);
const totalGuilds = results.reduce((sum, value) => sum + value, 0);

console.log(`Total guilds: ${totalGuilds}`);

broadcastEval runs the function you give it inside each shard's own process and returns an array of results, one element per shard. You then merge them with reduce. The same pattern applies for total user count:

const memberResults = await client.shard.broadcastEval(
  c => c.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0)
);
const totalMembers = memberResults.reduce((a, b) => a + b, 0);

There's a critical rule here: the function you pass to broadcastEval cannot directly access variables outside it, because it runs in another process. To pass in outside values you use context:

const guildId = '123456789012345678';

const names = await client.shard.broadcastEval(
  (c, { targetId }) => {
    const guild = c.guilds.cache.get(targetId);
    return guild ? guild.name : null;
  },
  { context: { targetId: guildId } }
);

const found = names.find(name => name !== null);

Since a given guild lives on only one shard, most results return null; you grab the populated one with find.

Memory, process count, and hybrid sharding

Because each shard is a separate Node.js process, RAM usage rises in direct proportion to the shard count. 16 shards roughly means 16 separate bot instances. On very large bots (tens of thousands of guilds) this can exhaust the server's memory.

The solution is hybrid sharding: grouping multiple shards into a single process (a cluster). discord.js's built-in ShardingManager doesn't offer this directly; for that the community package discord-hybrid-sharding is used. The logic is this: if you split 32 shards into 4 clusters, only 4 processes are launched, each carrying 8 shards. This drops the memory footprint significantly. Small and mid-sized bots don't need it; the standard ShardingManager is more than enough.

A few practical points when planning your process count:

  • Trim the cache: Don't enable unnecessary intents and caches; since each shard keeps its own cache, waste has a multiplier effect.
  • Process vs worker mode: ShardingManager launches separate processes by default; with mode: 'worker' you can use worker_threads instead, but isolation is stronger in process mode.
  • Respawning: with the respawn option enabled, a crashed shard comes back up automatically.

Frequently Asked Questions

Should I shard before my bot reaches 2500 guilds?

No, you don't need to. Discord lets you connect with a single shard up to 2500 guilds. Until you approach that limit, sharding only adds needless complexity and memory usage. When you do get close, switching to ShardingManager is a job of just a few files — don't bother early.

Should I set the shard count manually or use 'auto'?

In most cases totalShards: 'auto' is best; discord.js asks for Discord's recommended count and spawns processes accordingly. Only consider a manual count if you have a custom distribution strategy (for example spreading across multiple machines).

If one shard crashes, does the whole bot go down?

No. Shards are independent processes; if one crashes the others keep running. Only the guilds on that shard temporarily stop responding. With respawn enabled, the ShardingManager restarts the crashed shard automatically, so the outage is brief.

Is it time for your bot to scale? If you need help building a sharding architecture, aggregating data with broadcastEval, or moving to hybrid sharding, get in touch with me — let's take your bot to a large scale together.

Bu kategorideki tüm yazılar →

Devamı için