Documentation Index
Fetch the complete documentation index at: https://mintlify.com/disgoorg/disgo/llms.txt
Use this file to discover all available pages before exploring further.
Sharding distributes your bot’s guilds across multiple gateway connections. This is required for bots in 2,500+ guilds and improves performance for large-scale bots.
When to use sharding
< 2,500 guilds
≥ 2,500 guilds
Use a single gateway connection:client, err := disgo.New(token,
bot.WithDefaultGateway(),
)
Simpler setup, easier to manage. Sharding is required by Discord:client, err := disgo.New(token,
bot.WithDefaultShardManager(),
)
Discord will close your connection if you don’t shard.
How sharding works
Sharding distributes guilds using a deterministic formula:
shardID = (guildID >> 22) % shardCount
Each shard:
- Maintains its own WebSocket connection
- Receives events only for its assigned guilds
- Has its own session that can be resumed independently
Discord recommends 1,000 guilds per shard for optimal performance.
Creating a shard manager
Automatic shard count
Let Discord determine the shard count:
import (
"github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/bot"
"github.com/disgoorg/disgo/gateway"
)
client, err := disgo.New(token,
bot.WithDefaultShardManager(),
bot.WithShardManagerConfigOpts(
sharding.WithGatewayConfigOpts(
gateway.WithIntents(
gateway.IntentGuilds,
gateway.IntentGuildMessages,
),
),
),
)
Manual shard count
Specify the exact number of shards:
import "github.com/disgoorg/disgo/sharding"
client, err := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithShardCount(4),
sharding.WithShardIDs(0, 1, 2, 3),
),
)
Shard manager configuration
Auto-scaling
Automatically split shards when they grow too large:
client, err := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithAutoScaling(true),
sharding.WithShardSplitCount(2), // Split into 2 shards
),
)
When a shard exceeds Discord’s limits, it’s automatically split into multiple smaller shards.
Partial sharding
Run only specific shards (useful for distributed systems):
// Instance 1: Shards 0-1
client1, _ := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithShardCount(4),
sharding.WithShardIDs(0, 1),
),
)
// Instance 2: Shards 2-3
client2, _ := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithShardCount(4),
sharding.WithShardIDs(2, 3),
),
)
Gateway options for all shards
client, err := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithGatewayConfigOpts(
gateway.WithIntents(gateway.IntentGuilds),
gateway.WithCompression(gateway.CompressionZstdStream),
gateway.WithPresenceOpts(
gateway.WithPresenceActivities(
discord.Activity{
Name: "across shards",
Type: discord.ActivityTypeGame,
},
),
),
),
),
)
Managing shards
Opening shards
// Open all shards
ctx := context.Background()
client.OpenShardManager(ctx)
// Open specific shard
err := client.ShardManager.OpenShard(ctx, 0)
// Close specific shard
client.ShardManager.CloseShard(ctx, 0)
// Close all shards
client.Close(ctx)
Accessing shards
import "github.com/disgoorg/snowflake/v2"
// Get shard for a specific guild
guildID := snowflake.ID(123456789)
shard := client.ShardManager.ShardByGuildID(guildID)
// Get shard by ID
shard := client.ShardManager.Shard(0)
if shard != nil {
latency := shard.Latency()
status := shard.Status()
}
// Iterate all shards
for shard := range client.ShardManager.Shards() {
log.Printf("Shard %d: %v latency",
shard.ShardID(),
shard.Latency(),
)
}
Per-shard operations
// Set presence for specific shard
err := client.SetPresenceForShard(ctx, 0,
gateway.WithPresenceActivities(
discord.Activity{
Name: "Shard 0",
Type: discord.ActivityTypeGame,
},
),
)
// Request members on specific shard
shard := client.ShardManager.Shard(0)
err := shard.Send(ctx,
gateway.OpcodeRequestGuildMembers,
gateway.MessageDataRequestGuildMembers{
GuildID: guildID,
Query: "",
Limit: 0,
Presences: true,
},
)
Shard lifecycle events
import "github.com/disgoorg/disgo/events"
client, err := disgo.New(token,
bot.WithDefaultShardManager(),
bot.WithEventListeners(&events.ListenerAdapter{
OnGuildReady: func(e *events.GuildReady) {
log.Printf("Guild %s ready on shard %d",
e.GuildID,
e.ShardID,
)
},
OnGuildsReady: func(e *events.GuildsReady) {
log.Printf("All guilds ready on shard %d", e.ShardID)
},
}),
)
Shard state persistence
Save and restore shard sessions:
import "github.com/disgoorg/disgo/sharding"
// Save shard states
type ShardStates map[int]sharding.ShardState
func saveShardStates(client *bot.Client) ShardStates {
states := make(ShardStates)
for shard := range client.ShardManager.Shards() {
if sessionID := shard.SessionID(); sessionID != nil {
states[shard.ShardID()] = sharding.ShardState{
SessionID: *sessionID,
Sequence: *shard.LastSequenceReceived(),
ResumeURL: *shard.ResumeURL(),
}
}
}
return states
}
// Restore shard states
func createWithStates(token string, states ShardStates) (*bot.Client, error) {
return disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithShardIDsWithStates(states),
),
)
}
Shard close handling
import "github.com/disgoorg/disgo/gateway"
client, err := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithCloseHandler(func(
shard gateway.Gateway,
err error,
reconnect bool,
) {
log.Printf("Shard %d closed: %v (reconnect=%v)",
shard.ShardID(),
err,
reconnect,
)
if !reconnect {
// Handle fatal errors
log.Printf("Shard %d cannot reconnect", shard.ShardID())
}
}),
),
)
Identify rate limiting
Discord limits how fast you can identify shards:
import "github.com/disgoorg/disgo/gateway"
client, err := disgo.New(token,
bot.WithShardManagerConfigOpts(
sharding.WithIdentifyRateLimiterConfigOpt(
gateway.WithIdentifyMaxConcurrency(1),
),
),
)
DisGo automatically handles identify rate limiting based on Discord’s recommendations.
You can identify at most max_concurrency shards simultaneously. Discord provides this value in the Gateway Bot endpoint. DisGo fetches and applies this automatically.
Calculating shard IDs
Manually calculate which shard a guild belongs to:
import "github.com/disgoorg/disgo/sharding"
guildID := snowflake.ID(123456789)
shardCount := 4
shardID := sharding.ShardIDByGuild(guildID, shardCount)
log.Printf("Guild %d belongs to shard %d", guildID, shardID)
Complete sharding example
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/bot"
"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/disgo/events"
"github.com/disgoorg/disgo/gateway"
"github.com/disgoorg/disgo/sharding"
)
func main() {
client, err := disgo.New(os.Getenv("TOKEN"),
bot.WithShardManagerConfigOpts(
// Let Discord decide shard count
// Or specify manually:
// sharding.WithShardCount(4),
// sharding.WithShardIDs(0, 1, 2, 3),
// Enable auto-scaling
sharding.WithAutoScaling(true),
sharding.WithShardSplitCount(2),
// Configure all shards
sharding.WithGatewayConfigOpts(
gateway.WithIntents(
gateway.IntentGuilds,
gateway.IntentGuildMessages,
gateway.IntentMessageContent,
),
gateway.WithCompression(gateway.CompressionZstdStream),
),
// Handle shard close events
sharding.WithCloseHandler(func(
shard gateway.Gateway,
err error,
reconnect bool,
) {
log.Printf("Shard %d: %v", shard.ShardID(), err)
}),
),
bot.WithEventListeners(&events.ListenerAdapter{
OnGuildReady: func(e *events.GuildReady) {
log.Printf("Guild %s ready (shard %d)",
e.GuildID,
e.ShardID,
)
},
OnGuildsReady: func(e *events.GuildsReady) {
log.Printf("Shard %d ready", e.ShardID)
// Count guilds on this shard
count := 0
for shard := range e.Client().ShardManager.Shards() {
if shard.ShardID() == e.ShardID {
// Get guilds for this shard...
}
}
log.Printf("Shard %d has %d guilds", e.ShardID, count)
},
OnMessageCreate: func(e *events.MessageCreate) {
if e.Message.Content == "!shardinfo" {
// Find which shard this guild is on
if e.GuildID != nil {
shard := e.Client().ShardManager.ShardByGuildID(*e.GuildID)
_, _ = e.Client().Rest.CreateMessage(
e.ChannelID,
discord.MessageCreate{
Content: fmt.Sprintf(
"Shard %d/%d - Latency: %v",
shard.ShardID(),
shard.ShardCount(),
shard.Latency(),
),
},
)
}
}
},
}),
)
if err != nil {
log.Fatal(err)
}
defer client.Close(context.Background())
// Open all shards
client.OpenShardManager(context.Background())
// Wait for interrupt
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGINT, syscall.SIGTERM)
<-s
log.Println("Shutting down...")
}
The shard manager opens shards sequentially, respecting Discord’s identify rate limits. For 16 shards with max_concurrency=1, this takes about 80 seconds (5 seconds per identify).