Skip to main content

Sharding

A NestJS wrapper around Discord.js ShardingManager that lets you orchestrate bot shards from a dedicated NestJS application context.

info

This module runs in the manager process — the process that spawns and supervises shard workers. It is separate from your bot application. If you are looking for a basic sharding setup without a dedicated NestJS context, see Techniques → Sharding.

Setup

Create a dedicated entry point for the manager process:

src/manager.ts
import { NestFactory } from '@nestjs/core';
import { ManagerModule } from './manager.module';

async function bootstrap() {
await NestFactory.createApplicationContext(ManagerModule);
}

bootstrap();

Then import NestCordShardingModule into your manager module:

src/manager.module.ts
import { Module } from '@nestjs/common';
import { join } from 'node:path';
import { NestCordShardingModule } from '@globalart/nestcord';

@Module({
imports: [
NestCordShardingModule.forRoot({
file: join(__dirname, 'main.js'),
token: process.env.DISCORD_TOKEN,
totalShards: 'auto',
}),
],
})
export class ManagerModule {}

main.js is the compiled entry point of your actual bot application (the one that imports NestCordModule). By default the module calls ShardingManager.spawn() automatically on init.

Module Options

NestCordShardingModuleOptions extends Discord.js ShardingManagerOptions:

PropertyTypeDefaultDescription
filestringPath to the compiled bot script file.
tokenstringDiscord bot token passed to the manager.
totalShardsnumber | 'auto''auto'Number of shards to spawn.
autoSpawnbooleantrueWhether to call spawn() automatically on module init.
spawnOptionsNestCordShardingSpawnOptionsOptions forwarded to ShardingManager.spawn().

NestCordShardingSpawnOptions:

PropertyTypeDefaultDescription
amountnumber | 'auto''auto'Number of shards to spawn.
delaynumber5500Delay in milliseconds between each shard spawn.
timeoutnumber30000Timeout in milliseconds to wait for a shard to ready.

Listeners

Use @OnShardingManager and @OnShard to react to shard lifecycle events directly in any provider:

src/shard-events.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { Shard } from 'discord.js';
import {
OnShardingManager,
OnShard,
NestCordShardingManagerEvents,
NestCordShardEvents,
} from '@globalart/nestcord';

@Injectable()
export class ShardEventsService {
private readonly logger = new Logger(ShardEventsService.name);

@OnShardingManager('shardCreate')
onShardCreate([shard]: NestCordShardingManagerEvents['shardCreate']) {
this.logger.log(`Shard #${shard.id} created`);
}

@OnShard('ready')
onShardReady([shard]: NestCordShardEvents['ready']) {
this.logger.log(`Shard #${shard.id} is ready`);
}

@OnShard('error')
onShardError([shard, error]: NestCordShardEvents['error']) {
this.logger.error(`Shard #${shard.id} error: ${error.message}`);
}

@OnShard('death')
onShardDeath([shard]: NestCordShardEvents['death']) {
this.logger.warn(`Shard #${shard.id} died`);
}
}

Don't forget to add ShardEventsService to the providers array of your ManagerModule.

ShardingManager Events (@OnShardingManager)

EventArgumentsDescription
shardCreateshard: ShardEmitted when a new shard is created.

Shard Events (@OnShard)

These listeners are automatically registered on every shard as it spawns.

EventArgumentsDescription
spawnshard, processEmitted when the shard process is spawned.
readyshardEmitted when the shard becomes ready.
reconnectingshardEmitted when the shard starts reconnecting.
resumeshardEmitted when the shard resumes its connection.
disconnectshardEmitted when the shard disconnects.
errorshard, error: ErrorEmitted when the shard encounters an error.
messageshard, messageEmitted when the shard sends a message to the manager.
deathshard, processEmitted when the shard process exits.

Providers

ShardingManager is injectable directly into any provider:

src/manager.service.ts
import { Injectable } from '@nestjs/common';
import { ShardingManager } from 'discord.js';

@Injectable()
export class ManagerService {
public constructor(private readonly shardingManager: ShardingManager) {}
}

Alternatively, use the NestCordShardingService wrapper for convenience methods:

src/manager.service.ts
import { Injectable } from '@nestjs/common';
import { NestCordShardingService } from '@globalart/nestcord';

@Injectable()
export class ManagerService {
public constructor(private readonly shardingService: NestCordShardingService) {}

async getGuildCount(): Promise<number> {
const counts = await this.shardingService.fetchClientValues('guilds.cache.size');
return (counts as number[]).reduce((acc, count) => acc + count, 0);
}

async broadcastReload(): Promise<void> {
await this.shardingService.broadcastEval((client) => client.guilds.cache.size);
}
}

NestCordShardingService API

MethodReturnsDescription
shardsCollection<number, Shard>All currently spawned shards.
spawn(options?)Promise<Collection<number, Shard>>Spawns shards (useful when autoSpawn is false).
broadcast(message)Promise<unknown[]>Sends a message to all shards.
broadcastEval(fn, opts?)Promise<T[]>Evaluates a function on all shard clients and returns results.
fetchClientValues(prop)Promise<unknown>Fetches a client property from all shards.
respawnAll(options?)Promise<Collection<number, Shard>>Kills and restarts all shards.

Async Configuration

src/manager.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { join } from 'node:path';
import { NestCordShardingModule } from '@globalart/nestcord';

@Module({
imports: [
ConfigModule.forRoot(),
NestCordShardingModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
file: join(__dirname, 'main.js'),
token: config.getOrThrow('DISCORD_TOKEN'),
totalShards: 'auto',
}),
}),
],
})
export class ManagerModule {}