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.

Slash commands are Discord’s modern way of handling bot commands. They provide autocomplete, validation, and a better user experience than traditional text commands.

Creating your first slash command

1

Define your commands

First, define the commands you want to create:
var commands = []discord.ApplicationCommandCreate{
    discord.SlashCommandCreate{
        Name:        "say",
        Description: "says what you say",
        Options: []discord.ApplicationCommandOption{
            discord.ApplicationCommandOptionString{
                Name:        "message",
                Description: "What to say",
                Required:    true,
            },
            discord.ApplicationCommandOptionBool{
                Name:        "ephemeral",
                Description: "If the response should only be visible to you",
                Required:    true,
            },
        },
    },
}
2

Register the commands

Register your commands with Discord after creating your client:
// For guild-specific commands (faster, recommended for development)
if _, err = client.Rest.SetGuildCommands(client.ApplicationID, guildID, commands); err != nil {
    slog.Error("error while registering commands", slog.Any("err", err))
}

// Or for global commands (slower, up to 1 hour to propagate)
if _, err = client.Rest.SetGlobalCommands(client.ApplicationID, commands); err != nil {
    slog.Error("error while registering commands", slog.Any("err", err))
}
Guild commands update instantly, while global commands can take up to an hour to propagate. Use guild commands during development.
3

Handle command interactions

Add an event listener to handle when users run your commands:
client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListenerFunc(commandListener),
)

func commandListener(event *events.ApplicationCommandInteractionCreate) {
    data := event.SlashCommandInteractionData()
    if data.CommandName() == "say" {
        err := event.CreateMessage(discord.MessageCreate{
            Content: data.String("message"),
            Flags: discord.MessageFlags(
                data.Bool("ephemeral"),
            ),
        })
        if err != nil {
            slog.Error("error on sending response", slog.Any("err", err))
        }
    }
}

Complete example

Here’s a complete working example:
package main

import (
    "context"
    "log/slog"
    "os"
    "os/signal"
    "syscall"

    "github.com/disgoorg/snowflake/v2"
    "github.com/disgoorg/disgo"
    "github.com/disgoorg/disgo/bot"
    "github.com/disgoorg/disgo/discord"
    "github.com/disgoorg/disgo/events"
)

var (
    token   = os.Getenv("disgo_token")
    guildID = snowflake.GetEnv("disgo_guild_id")

    commands = []discord.ApplicationCommandCreate{
        discord.SlashCommandCreate{
            Name:        "say",
            Description: "says what you say",
            Options: []discord.ApplicationCommandOption{
                discord.ApplicationCommandOptionString{
                    Name:        "message",
                    Description: "What to say",
                    Required:    true,
                },
                discord.ApplicationCommandOptionBool{
                    Name:        "ephemeral",
                    Description: "If the response should only be visible to you",
                    Required:    true,
                },
            },
        },
    }
)

func main() {
    client, err := disgo.New(token,
        bot.WithDefaultGateway(),
        bot.WithEventListenerFunc(commandListener),
    )
    if err != nil {
        slog.Error("error while building disgo instance", slog.Any("err", err))
        return
    }

    defer client.Close(context.TODO())

    if _, err = client.Rest.SetGuildCommands(client.ApplicationID, guildID, commands); err != nil {
        slog.Error("error while registering commands", slog.Any("err", err))
    }

    if err = client.OpenGateway(context.TODO()); err != nil {
        slog.Error("error while connecting to gateway", slog.Any("err", err))
    }

    slog.Info("bot is now running. Press CTRL-C to exit.")
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
    <-s
}

func commandListener(event *events.ApplicationCommandInteractionCreate) {
    data := event.SlashCommandInteractionData()
    if data.CommandName() == "say" {
        err := event.CreateMessage(discord.NewMessageCreate().
            WithContent(data.String("message")).
            WithEphemeral(data.Bool("ephemeral")),
        )
        if err != nil {
            slog.Error("error on sending response", slog.Any("err", err))
        }
    }
}

Command options

DisGo supports all Discord command option types:
discord.ApplicationCommandOptionString{
    Name:        "text",
    Description: "Enter some text",
    Required:    true,
    MaxLength:   100,
    MinLength:   1,
}

Subcommands and groups

You can organize commands into subcommands and groups:
discord.SlashCommandCreate{
    Name:        "admin",
    Description: "Admin commands",
    Options: []discord.ApplicationCommandOption{
        discord.ApplicationCommandOptionSubCommandGroup{
            Name:        "user",
            Description: "User management",
            Options: []discord.ApplicationCommandOptionSubCommand{
                {
                    Name:        "ban",
                    Description: "Ban a user",
                    Options: []discord.ApplicationCommandOption{
                        discord.ApplicationCommandOptionUser{
                            Name:        "target",
                            Description: "User to ban",
                            Required:    true,
                        },
                    },
                },
                {
                    Name:        "kick",
                    Description: "Kick a user",
                    Options: []discord.ApplicationCommandOption{
                        discord.ApplicationCommandOptionUser{
                            Name:        "target",
                            Description: "User to kick",
                            Required:    true,
                        },
                    },
                },
            },
        },
    },
}

Localization

You can localize command names and descriptions:
discord.SlashCommandCreate{
    Name: "say",
    NameLocalizations: map[discord.Locale]string{
        discord.LocaleEnglishGB: "say",
        discord.LocaleGerman:    "sagen",
        discord.LocaleFrench:    "dire",
    },
    Description: "says what you say",
    DescriptionLocalizations: map[discord.Locale]string{
        discord.LocaleEnglishGB: "says what you say",
        discord.LocaleGerman:    "sagt was du sagst",
        discord.LocaleFrench:    "dit ce que vous dites",
    },
}

Using the handler package

DisGo provides a router-style handler for cleaner command organization:
import "github.com/disgoorg/disgo/handler"

r := handler.New()
r.SlashCommand("/say", handleSay)
r.SlashCommand("/admin/user/ban", handleBan)

client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListeners(r),
)

func handleSay(data discord.SlashCommandInteractionData, e *handler.CommandEvent) error {
    return e.CreateMessage(discord.MessageCreate{
        Content: data.String("message"),
    })
}
The handler package makes it easier to organize complex bots with many commands. It supports middleware, routing patterns, and more.

Best practices

  • Use ephemeral responses for error messages and sensitive information
  • Validate user input even though Discord provides basic validation
  • Handle errors gracefully and provide helpful error messages
  • Use guild commands during development for instant updates
  • Add helpful descriptions to make your commands easy to understand
  • Consider localization if your bot serves international users

Next steps