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.
DisGo’s caching system stores Discord entities in memory, reducing API calls and improving response times. You have full control over what gets cached and how.
Why use caching?
Caching provides:
- Fast data access - No API calls needed for cached data
- Reduced rate limiting - Fewer REST requests
- Offline data - Access entity data even if Discord’s API is slow
- Historical data - Track changes (old vs new messages, members, etc.)
Cache structure
The cache system is organized by entity type:
type Caches interface {
SelfUserCache // Bot's user object
GuildCache // Guilds
ChannelCache // Channels
RoleCache // Roles
MemberCache // Guild members
MessageCache // Messages
VoiceStateCache // Voice states
PresenceCache // User presences
EmojiCache // Custom emojis
StickerCache // Custom stickers
// ... and more
}
Enabling caches
Control which entities are cached using flags:
import "github.com/disgoorg/disgo/cache"
client, err := disgo.New(token,
bot.WithCacheConfigOpts(
cache.WithCaches(
cache.FlagGuilds,
cache.FlagChannels,
cache.FlagRoles,
cache.FlagMembers,
),
),
)
Available cache flags
Cache all channel types (text, voice, threads, etc.)
Cache user presences (requires IntentGuildPresences)
Accessing cached data
All cached data is available through the client:
import "github.com/disgoorg/snowflake/v2"
// Get a guild
guild, ok := client.Caches.Guild(guildID)
if ok {
log.Printf("Guild: %s", guild.Name)
}
// Get a channel
channel, ok := client.Caches.Channel(channelID)
if ok {
log.Printf("Channel: %s", channel.Name())
}
// Get a member
member, ok := client.Caches.Member(guildID, userID)
if ok {
log.Printf("Member: %s", member.User.Username)
}
// Get a message
message, ok := client.Caches.Message(channelID, messageID)
if ok {
log.Printf("Content: %s", message.Content)
}
Iterating cached entities
// Iterate all guilds
for guild := range client.Caches.Guilds() {
log.Println(guild.Name)
}
// Iterate channels in a guild
for channel := range client.Caches.ChannelsForGuild(guildID) {
log.Println(channel.Name())
}
// Iterate members in a guild
for member := range client.Caches.Members(guildID) {
log.Println(member.User.Username)
}
// Count cached entities
guildCount := client.Caches.GuildsLen()
memberCount := client.Caches.MembersLen(guildID)
Cache policies
Cache policies control which entities get cached:
import "github.com/disgoorg/disgo/cache"
client, err := disgo.New(token,
bot.WithCacheConfigOpts(
cache.WithCaches(cache.FlagMembers),
// Only cache members in specific guilds
cache.WithMemberCachePolicy(
cache.PolicyMembersInclude(
snowflake.ID(123456789),
snowflake.ID(987654321),
),
),
),
)
Built-in policies
All
None
Specific guilds
Pending members
Voice members
Cache everything:cache.WithMemberCachePolicy(cache.PolicyAll[discord.Member])
Cache nothing (disable cache):cache.WithMemberCachePolicy(cache.PolicyNone[discord.Member])
Cache members only in certain guilds:cache.WithMemberCachePolicy(
cache.PolicyMembersInclude(guildID1, guildID2),
)
Cache only pending members:cache.WithMemberCachePolicy(
cache.PolicyMembersPending,
)
Cache only members in voice channels:// Note: You need to pass the caches instance
cache.WithMemberCachePolicy(
cache.PolicyMembersInVoice(caches),
)
Custom policies
Create your own cache policies:
import "github.com/disgoorg/disgo/discord"
// Cache only messages with attachments
cache.WithMessageCachePolicy(
cache.Policy[discord.Message](func(msg discord.Message) bool {
return len(msg.Attachments) > 0
}),
)
// Cache only text channels
cache.WithChannelCachePolicy(
cache.PolicyChannelInclude(
discord.ChannelTypeGuildText,
discord.ChannelTypeGuildNews,
),
)
// Exclude category channels
cache.WithChannelCachePolicy(
cache.PolicyChannelExclude(
discord.ChannelTypeGuildCategory,
),
)
Combining policies
// Cache members in voice OR pending members
policy := cache.PolicyMembersInVoice(caches).Or(
cache.PolicyMembersPending,
)
cache.WithMemberCachePolicy(policy)
// Cache members in voice AND in specific guilds
policy := cache.PolicyMembersInVoice(caches).And(
cache.PolicyMembersInclude(guildID),
)
cache.WithMemberCachePolicy(policy)
Utility methods
The cache provides helper methods for common operations:
Permission calculation
// Calculate member permissions in guild
member, _ := client.Caches.Member(guildID, userID)
perms := client.Caches.MemberPermissions(member)
if perms.Has(discord.PermissionAdministrator) {
log.Println("Member is admin")
}
// Calculate permissions in specific channel
channel, _ := client.Caches.Channel(channelID)
perms = client.Caches.MemberPermissionsInChannel(channel, member)
if perms.Has(discord.PermissionSendMessages) {
log.Println("Can send messages")
}
Member roles
member, _ := client.Caches.Member(guildID, userID)
roles := client.Caches.MemberRoles(member)
for _, role := range roles {
log.Printf("Role: %s", role.Name)
}
Voice channel members
import "github.com/disgoorg/disgo/discord"
channel, _ := client.Caches.GuildVoiceChannel(channelID)
members := client.Caches.AudioChannelMembers(channel)
log.Printf("%d members in voice", len(members))
Self member
// Get the bot's member object in a guild
selfMember, ok := client.Caches.SelfMember(guildID)
if ok {
log.Printf("Bot nickname: %s", selfMember.Nick)
}
Custom cache implementation
You can provide your own cache implementation:
import "github.com/disgoorg/disgo/cache"
type MyCache struct {
// Your custom storage
}
func (c *MyCache) Get(id snowflake.ID) (discord.Guild, bool) {
// Your implementation
}
func (c *MyCache) Put(id snowflake.ID, guild discord.Guild) {
// Your implementation
}
// Use it
client, err := disgo.New(token,
bot.WithCacheConfigOpts(
cache.WithGuildCache(
cache.NewGuildCache(
&MyCache{},
cache.NewSet[snowflake.ID](),
cache.NewSet[snowflake.ID](),
),
),
),
)
Events and caching
Events provide both current and old cached values:
OnMessageUpdate: func(e *events.MessageUpdate) {
log.Printf("Old content: %s", e.OldMessage.Content)
log.Printf("New content: %s", e.Message.Content)
},
OnGuildMemberUpdate: func(e *events.GuildMemberUpdate) {
// Check if roles changed
addedRoles := difference(e.Member.RoleIDs, e.OldMember.RoleIDs)
removedRoles := difference(e.OldMember.RoleIDs, e.Member.RoleIDs)
},
Old values are only available if the entity was previously cached. If the cache flag wasn’t enabled, OldMessage and similar fields will be empty.
Cache best practices
Enable only what you need
Each cache flag increases memory usage. Only enable caches you actually use.// Good: Only cache what you need
cache.WithCaches(
cache.FlagGuilds,
cache.FlagChannels,
)
// Bad: Caching everything
cache.WithCaches(
cache.FlagGuilds | cache.FlagChannels |
cache.FlagMembers | cache.FlagMessages | // ...
)
Use cache policies for large bots
For bots in many guilds, use policies to limit memory:// Cache members only in guilds you moderate
cache.WithMemberCachePolicy(
cache.PolicyMembersInclude(moderatedGuildIDs...),
)
Fallback to API calls
Always handle cache misses:member, ok := client.Caches.Member(guildID, userID)
if !ok {
// Fetch from API
member, err := client.Rest.GetMember(guildID, userID)
}
Complete example
package main
import (
"log"
"github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/bot"
"github.com/disgoorg/disgo/cache"
"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/disgo/events"
"github.com/disgoorg/disgo/gateway"
)
func main() {
client, err := disgo.New(token,
bot.WithGatewayConfigOpts(
gateway.WithIntents(
gateway.IntentGuilds,
gateway.IntentGuildMembers,
gateway.IntentGuildMessages,
),
),
bot.WithCacheConfigOpts(
// Enable specific caches
cache.WithCaches(
cache.FlagGuilds,
cache.FlagChannels,
cache.FlagRoles,
cache.FlagMembers,
cache.FlagMessages,
),
// Limit member cache to reduce memory
cache.WithMemberCachePolicy(
cache.PolicyMembersInclude(
snowflake.ID(123456789), // Only cache in this guild
),
),
// Only cache messages with attachments
cache.WithMessageCachePolicy(
cache.Policy[discord.Message](func(msg discord.Message) bool {
return len(msg.Attachments) > 0
}),
),
),
bot.WithEventListeners(&events.ListenerAdapter{
OnGuildMemberJoin: func(e *events.GuildMemberJoin) {
// Member is automatically cached
guild, _ := e.Client().Caches.Guild(e.GuildID)
log.Printf("%s joined %s (total: %d)",
e.Member.User.Username,
guild.Name,
e.Client().Caches.MembersLen(e.GuildID),
)
},
OnMessageCreate: func(e *events.MessageCreate) {
if e.Message.Content == "!members" {
// Use cached data
count := 0
for range e.Client().Caches.Members(*e.GuildID) {
count++
}
_, _ = e.Client().Rest.CreateMessage(
e.ChannelID,
discord.MessageCreate{
Content: fmt.Sprintf("Cached members: %d", count),
},
)
}
},
}),
)
if err != nil {
log.Fatal(err)
}
// ... connect and run
}
Message caching can use significant memory for active bots. Consider using cache.FlagNone for messages or a restrictive policy if you don’t need message history.