Bot Client
Overview
bot.Bot is the top-level object for a high-level application. It owns the gateway connection, typed event dispatch, command router, REST client, optional cache and store, presence, jobs, and lifecycle state. Create one bot per process and register handlers before starting it.
Architecture
bot.New applies functional options to a Bot. The bot creates a default rest.Client unless WithRESTClient supplies one. Start creates either one gateway client or a shard manager, then dispatches each event to registered handlers in separate goroutines. Context helpers retain a reference to the bot and its REST client, so a MessageContext or InteractionContext can perform common operations without rebuilding a request.
Bot.Rest is public for direct endpoint access; Bot.RestClient() is the method-based accessor that returns the same client. Bot.Store is application-owned persistence and is not a Discord cache.
Quick Start
This complete program creates a client, logs READY, and registers a command.
package main
import (
"log"
"os"
"github.com/discord-go/discord.go/bot"
"github.com/discord-go/discord.go/intents"
)
func main() {
token := os.Getenv("DISCORD_TOKEN")
if token == "" {
log.Fatal("DISCORD_TOKEN is required")
}
router := bot.NewRouter()
router.Command("ping", "Check the client", func(ctx *bot.InteractionContext) {
if err := ctx.Reply("The client is running"); err != nil {
log.Printf("reply: %v", err)
}
})
client := bot.New(token, bot.WithIntents(intents.Guilds), bot.WithRouter(router))
client.OnReady(func(ctx *bot.ReadyContext) {
log.Printf("ready as %s", ctx.User.Username)
})
if err := client.Run(); err != nil {
log.Fatal(err)
}
}Run it with DISCORD_TOKEN=... go run .. The bot token must belong to an application installed with the bot and applications.commands scopes.
Creating/Configuration
The constructor is bot.New(token string, opts ...bot.Option) *bot.Bot. Common options are:
WithIntents(intents.Intent)sets gateway subscriptions.WithPrefix(string),WithBotName(string), andWithMentionTriggers(bool)control text-command triggers.WithRouter(*bot.Router)attaches slash, prefix, and component routing.WithRESTClient(*rest.Client)replaces the default REST transport.WithCache(cache.Cache)enables cache hydration and typed helpers.WithStore(storage.Store)attaches application persistence.WithLogger(*log.Logger)andWithErrorHandler(bot.ErrorHandler)configure diagnostics.WithGatewayCompression(bool),WithShards(int), andWithMaxHandlerConcurrency(int)tune runtime behavior.WithCommandSync(bot.CommandSyncConfig)orWithGuildCommandSync(snowflake.ID)controls command registration.
For JSON and environment-driven construction, see configuration.md.
Using
Basic: inspect the client
State, IsReady, WaitReady, User, AppID, ReadyAt, Uptime, and RestClient are safe to call while the bot is running. User returns a copy of the READY user. RestClient returns the REST client (the same one exposed by the Rest field).
Intermediate: use direct REST
For example, client.RestClient().GetCurrentUser(ctx) performs a request not tied to an event. Always pass a context with cancellation or a deadline for long work.
Advanced: replace transports
Use WithRESTClient for a custom HTTP client or limiter, and WithConnectionFactory for a gateway proxy or test connection. These options are useful for infrastructure integration, not normal bot setup.
Common Patterns
- Register all handlers before
Run; registration methods are safe but setup is easier to reason about when it is single-threaded. - Keep one shared router and pass it to
WithRouter. - Use
WithMaxHandlerConcurrencywhen unbounded event-handler goroutines could overload an external service. - Keep
Bot.Storefor application records andWithCachefor disposable Discord resource snapshots.
Best Practices
Request least privilege
Why: intents determine which gateway events Discord sends and some are privileged.
Pros: less data, simpler privacy review, and lower event volume.
Cons: a missing intent can make a handler appear broken until the portal and code are both updated.
Make lifecycle ownership explicit
Why: Run owns OS signals, while RunContext and Start let a service own cancellation.
Pros: clean tests and predictable shutdown.
Cons: the caller must wait for Stop or Wait instead of abandoning the process.
Keep the public REST client centralized
Why: the bot's client already carries authentication, rate limiting, and base URL configuration.
Pros: consistent requests and fewer leaked tokens.
Cons: code that needs a different auth mode must intentionally use another rest.Client.
Common Mistakes
Incorrect: constructing a bot with no token and expecting Run to discover it.
client := bot.New("")
_ = client.Run()Correct: load the token before construction.
token := os.Getenv("DISCORD_TOKEN")
if token == "" {
log.Fatal("DISCORD_TOKEN is required")
}
client := bot.New(token)Incorrect: treating Start as a blocking call.
_ = client.Start(context.Background())
// The process exits immediately.Correct: wait for readiness and termination, or use Run.
if err := client.Start(ctx); err != nil {
return err
}
if err := client.WaitReady(ctx); err != nil {
return err
}
return client.Wait()API Walkthrough
bot.BotcontainsRest *rest.ClientandStore storage.Storefor direct access to configured clients.bot.Newcreates the object;bot.WithIntents,WithPrefix,WithBotName,WithMentionTriggers,WithGatewayCompression,WithPresence,WithShards,WithRouter,WithRESTClient,WithCache,WithStore,WithLogger,WithErrorHandler,WithGatewayURL,WithConnectionFactory,WithMaxHandlerConcurrency,WithCommandSync,WithCommandSyncDisabled, andWithGuildCommandSyncreturnbot.Optionvalues.bot.Bot.OnReady,OnMessageCreate,OnMessageUpdate,OnMessageDelete,OnInteraction,OnInteractionCreate,OnMessageReactionAdd,OnGuildCreate,OnGuildUpdate,OnGuildDelete,OnChannelCreate,OnChannelUpdate,OnGuildAuditLogEntryCreate,OnRawEvent, andOnErrorregister handlers.OnEventandOnreturn an unsubscribe function for named dispatch events;OnceEventandOnceremove the handler after its first call.State,Done,Wait,Start,Run,RunContext,Stop,WaitReady,IsReady,AppID,User,ReadyAt,Uptime,Stats,GatewayLatency,APILatency, andRestClientexpose lifecycle and runtime state.BotStatehasBotStateStopped,BotStateStarting,BotStateRunning, andBotStateStopping.CommandSyncConfigcontainsMode,GuildID, andTimeout; modes areCommandSyncGlobal,CommandSyncGuild, andCommandSyncDisabled.
Examples
Related APIs
lifecycle.mdfor service startup and shutdown.commands.mdfor routing.errors.mdfor diagnostics.../low-level/client/README.mdfor lower-level client concepts.../low-level/rest/README.mdfor direct REST calls.