Skip to content

Sharding

Discord requires bots in more than 2,500 guilds to use sharding — splitting the bot across multiple processes, each managing a subset of guilds. Popii ships two utilities for this: autoShard (recommended) and PopiiShardingManager (manual).

Discord’s hard limit is 2,500 guilds per shard. Below that, your bot runs in a single process and needs no changes. Above it, Discord will refuse Gateway connections unless you shard.

autoShard queries Discord for the recommended shard count, then decides automatically:

  • Below threshold → starts your bot as a normal single process (no overhead).
  • At or above threshold → spawns a PopiiShardingManager with the correct shard count.

Create a separate shard.ts entry point:

shard.ts
import { autoShard } from "popii-framework";
await autoShard({
token: process.env.DISCORD_TOKEN!,
file: "./src/index.ts", // default — your normal bot entry point
threshold: 2_500, // default — activate sharding above this guild count
});

Run shard.ts instead of src/index.ts in production:

package.json
{
"scripts": {
"start": "bun run shard.ts",
"dev": "bun run src/index.ts"
}
}

Your src/index.ts stays unchanged — it doesn’t need to know about sharding.

Use this when you want explicit control over the shard count or lifecycle:

shard.ts
import { PopiiShardingManager } from "popii-framework";
const manager = new PopiiShardingManager({
token: process.env.DISCORD_TOKEN!,
file: "./src/index.ts",
totalShards: "auto", // let Discord decide, or pass a number
});
await manager.spawn();
OptionTypeDefaultDescription
tokenstringrequiredYour Discord bot token
filestring"./src/index.ts"Entry point for each shard process
totalShardsnumber | "auto""auto"Number of shards to spawn

All other options from discord.js ShardingManagerOptions are passed through.

PopiiShardingManager supports zero-downtime rolling restarts — shards restart one at a time, so there’s always capacity while the update applies:

await manager.rollingRestart();

To trigger a rolling restart from inside a shard (e.g. from a bot command):

// The shard sends a message to the manager
process.send?.({ _popii_sharding_action: "rolling_restart" });

Redis — required for cross-shard features

Section titled “Redis — required for cross-shard features”

Several features only work across shards when Redis is connected:

FeatureRequires Redis
Shared cooldownsYes
pop.cooler persistenceYes
client.broadcast() cross-shard eventsYes
presenceStrategy: "coordinated"Yes
Persistent pop.stateYes

Configure Redis in popiiClient():

const client = popiiClient({
token: process.env.DISCORD_TOKEN!,
redisUrl: process.env.REDIS_URL,
});

Emit an event on one shard and listen on all others:

// Emit from any shard
await pop.client.broadcast("cache-invalidate", { userId: pop.user.id });
// Listen on all shards (in a plugin's setup hook)
client.onBroadcast("cache-invalidate", ({ userId }) => {
userCache.delete(userId);
});

Under the hood, Popii uses Redis pub/sub when Redis is connected, or Discord.js IPC when it’s not. IPC is limited to shards on the same machine.

OptionTypeDefaultDescription
tokenstringrequiredYour Discord bot token
filestring"./src/index.ts"Bot entry point
thresholdnumber2500Guild count below which no ShardingManager is used
totalShardsnumber | "auto"Discord-recommendedForwarded to PopiiShardingManager when sharding activates

All other PopiiShardingOptions (which extend discord.js ShardingManagerOptions) are forwarded as-is.