Commands And Routing
Overview
bot.Router turns Discord commands into application handlers. It supports chat input slash commands, user and message context-menu commands, prefix commands, aliases, global and local middleware, and interaction routes for buttons, selects, modals, and autocomplete.
Architecture
The router stores commands by normalized name. When an interaction arrives, it first identifies the command or custom-ID route, then wraps the handler with command middleware and global middleware. Prefix messages are tokenized with quoted values preserved, validated, and passed to a PrefixHandler.
Attaching a router with bot.WithRouter enables automatic command sync on READY. The default is global sync; bot.WithGuildCommandSync is faster for development. The router only registers definitions. Discord still decides whether an application is installed and whether a user can see a command.
Quick Start
This program registers a slash command with a string option and a prefix alias.
package main
import (
"log"
"os"
"github.com/discord-go/discord.go/bot"
"github.com/discord-go/discord.go/intents"
"github.com/discord-go/discord.go/interactions"
)
func main() {
token := os.Getenv("DISCORD_TOKEN")
if token == "" {
log.Fatal("DISCORD_TOKEN is required")
}
router := bot.NewRouter()
router.Command("hello", "Greet a person", func(ctx *bot.InteractionContext) {
name := ctx.GetStringOption("name")
if name == "" {
name = "friend"
}
if err := ctx.Reply("Hello, " + name); err != nil {
log.Printf("reply: %v", err)
}
}, interactions.ApplicationCommandOption{
Type: interactions.ApplicationCommandOptionTypeString,
Name: "name",
Description: "Name to greet",
})
router.Prefix("hello", func(ctx *bot.MessageContext, args []string) {
_, err := ctx.Reply("Hello from a prefix command")
if err != nil {
log.Printf("reply: %v", err)
}
}).Aliases("hi")
b := bot.New(token,
bot.WithIntents(intents.Guilds|intents.GuildMessages|intents.MessageContent),
bot.WithRouter(router),
)
if err := b.Run(); err != nil {
log.Fatal(err)
}
}Prefix dispatch requires GuildMessages and MessageContent, plus the corresponding portal configuration. Use a test guild while developing command definitions.
Creating/Configuration
Create a router with bot.NewRouter() *bot.Router. Register chat input commands with Command(name, description string, handler CommandHandler, opts ...interactions.ApplicationCommandOption). Use ContextCommand, UserCommand, or MessageCommand for context menus. Use Prefix(name string, handler PrefixHandler) for text commands.
CommandE returns (*Command, error) and validates immediately. MustCommand panics on invalid static setup. Router.Validate() can validate the whole registry before startup. WithCommandSync controls whether READY automatically calls BulkOverwriteGlobalCommands or BulkOverwriteGuildCommands.
Using
Basic: slash and context commands
Options are interactions.ApplicationCommandOption values. Names and descriptions must satisfy Discord's limits. In a context command, use ctx.TargetID() to get the selected user or message ID.
Intermediate: middleware and prefix commands
Call router.Use(middleware) for every slash command or command.Use(...) for one command. Prefix commands have their own PrefixMiddleware type. Configure MinArgs, Usage, Validate, Description, and Aliases fluently.
Advanced: routes and registry introspection
Use Button, ButtonPrefix, Select, SelectPrefix, Modal, and Autocomplete for non-command interactions. Commands, Lookup, CommandCount, HasCommand, and RangeCommands support help output and startup checks. RemoveCommand and RemovePrefix support dynamic registries.
Common Patterns
- Use
CommandEin tests to catch duplicate and malformed definitions. - Prefer a stable custom-ID prefix for routes that contain IDs.
- Use guild sync for development and disable automatic sync when another deploy system owns command registration.
- Keep handlers thin and move business logic into functions that accept a context and return an error.
- Use
Cooldown,GuildOnly, and permission middleware before expensive work.
Best Practices
Validate at registration time
Why: malformed names and options otherwise fail during READY synchronization.
Pros: failures are local, deterministic, and easy to test.
Cons: Command itself replaces duplicates and reports them through the bot error handler, so CommandE is preferable when setup must fail immediately.
Separate command types
Why: prefix handlers receive message arguments while interaction handlers receive structured options and a three-second initial response window.
Pros: each handler has the correct data and response semantics.
Cons: shared behavior needs a small application service rather than one handler being reused blindly.
Make custom IDs data-safe
Why: component routes match exact IDs or prefixes, not arbitrary application state.
Pros: routes are simple and stateless.
Cons: long or user-controlled IDs can exceed Discord limits or create collisions; validate and encode values before constructing them.
Common Mistakes
Incorrect: using an uppercase slash command name.
router.Command("Hello World", "Greeting", handler)Correct: use lowercase letters, digits, hyphens, or underscores and a valid description.
router.Command("hello-world", "Send a greeting", handler)Incorrect: assuming a prefix command receives quoted words separately.
// !say "hello world" is expected to produce two arguments.Correct: quoted values remain one argument.
router.Prefix("say", func(ctx *bot.MessageContext, args []string) {
// !say "hello world" produces []string{"hello world"}.
})API Walkthrough
CommandHandlerisfunc(*InteractionContext);PrefixHandlerisfunc(*MessageContext, []string).Middleware,PrefixMiddleware, andPrefixValidationwrap or validate handlers.Router.Use,Command.Use, andInteractionRoute.Useadd middleware.CommandhasName,Description,Type,Options,Handler, andCategory;InCategory,Cooldown,RequirePermissions, andRequireBotPermissionsreturn the command for chaining.PrefixCommand.Use,Description,Usage,MinArgs,Validate, andAliasesconfigure text commands.Command,CommandE,MustCommand,ContextCommand,UserCommand,MessageCommand,Prefix,RemoveCommand,RemovePrefix,Lookup,HasCommand,CommandCount,Commands,RangeCommands, andValidateare the command registry methods.Button,ButtonPrefix,Select,SelectPrefix,Modal, andAutocompleteregisterInteractionRoutevalues.InteractionRoute.IDandHandleridentify the route.interactions.ApplicationCommandOptiondescribesType,Name,Description,Required,Choices,Autocomplete, value bounds, localization, string lengths, and channel types.- Option types include
SubCommand,SubCommandGroup,String,Integer,Boolean,User,Channel,Role,Mentionable,Number, andAttachment. interactions.NewSlashCommandBuilderand itsSetName,SetDescription,AddStringOption,AddStringOptionWithChoices,AddIntegerOption,AddBooleanOption,AddUserOption,AddChannelOption,AddRoleOption,AddMentionableOption,AddOption,SetIntegrationTypes,SetContexts, andBuildmethods create a low-level command value for direct REST use. TheseAdd*Optionmethods are not available on the*bot.Commandreturned byrouter.Command; for the high-level router, passinteractions.ApplicationCommandOptionvalues as variadic arguments.
Examples
Related APIs
interactions.mdfor reading options and responding.buttons.mdandmodals.mdfor component routes.permissions.mdfor command middleware.../low-level/rest/endpoints.mdfor manual command sync.