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.

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
filestring—Path to the compiled bot script file.
tokenstring—Discord bot token passed to the manager.
totalShardsnumber | 'auto''auto'Number of shards to spawn.
autoSpawnbooleantrueWhether to call spawn() automatically on module init.
spawnOptionsNestCordShardingSpawnOptions—Options 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: Shard) {
this.logger.log(`Shard #${shard.id} created`);
}

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

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

@OnShard('death')
onShardDeath(shard: Shard) {
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 {}