Skip to main content

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

FlagGuilds
Flags
Cache guild objects
FlagChannels
Flags
Cache all channel types (text, voice, threads, etc.)
FlagRoles
Flags
Cache roles
FlagMembers
Flags
Cache guild members
FlagMessages
Flags
Cache messages
FlagVoiceStates
Flags
Cache voice states
FlagPresences
Flags
Cache user presences (requires IntentGuildPresences)
FlagEmojis
Flags
Cache custom emojis
FlagStickers
Flags
Cache custom stickers

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

Cache everything:
cache.WithMemberCachePolicy(cache.PolicyAll[discord.Member])

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

1

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 | // ...
)
2

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...),
)
3

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.

Build docs developers (and LLMs) love