Skip to content

Slash Commands

This guide covers registering a global slash command and responding to it when a user runs it.

Use builders.interaction.interaction to describe the command before registering it.

local discord = require("@self/../luau_packages/discord")
local classes = require("@self/../luau_packages/classes")
local builders = require("@self/../luau_packages/builders")
local env = require("@self/../.env")
local pingCommand = builders.interaction.interaction.new()
:setName("ping")
:setDescription("Replies with Pong!")
:setType("ChatInput")
:addIntegrationType("GuildInstall")
:addContext("Guild")
:build()
MethodRequiredNotes
:setName(name)Yes1-32 characters, lowercase
:setDescription(desc)Yes1-100 characters
:setType(type)No"ChatInput" for slash commands (default when omitted)
:addIntegrationType(type)YesAt least one - "GuildInstall" or "UserInstall"
:addContext(context)YesAt least one - "Guild", "BotDm", or "PrivateChannel"

Global commands are registered via bot.application, which is available after onAllShardsReady. Registration is asynchronous - global commands can take up to an hour to propagate to all Discord servers.

local bot = discord.bot.new({
token = env.DISCORD_BOT_TOKEN,
intents = builders.intents.new({ "Guilds" }):build(),
reconnect = true,
})
bot.onAllShardsReady:listenOnce(function()
local result = bot.application:createSlashCommandAsync(pingCommand):await()
if result:isErr() then
warn("Failed to register command:", result:unwrapErr())
return
end
print("Registered command:", result:unwrapOk().name)
end)

Listen to bot.onCommandInteraction to receive slash command interactions. The interaction object provides :messageAsync() to send a response.

bot.onCommandInteraction:listen(function(interaction: classes.TypesCommand)
if interaction.data.name ~= "ping" then
return
end
interaction:messageAsync(
builders.message.message.new()
:setContent("Pong!")
:build()
):await()
end)
bot:connectAsync():await()

Use builders.interaction.option to add parameters to a command. Options must be built and passed to :addOption() before calling :build() on the command.

local greetCommand = builders.interaction.interaction.new()
:setName("greet")
:setDescription("Greet a user by name")
:setType("ChatInput")
:addIntegrationType("GuildInstall")
:addContext("Guild")
:addOption(
builders.interaction.option.new()
:setType("String")
:setName("name")
:setDescription("The name to greet")
:build()
)
:build()

If your handler needs more than three seconds (e.g. to fetch data), defer the interaction first to show a loading state, then edit the response when ready.

bot.onCommandInteraction:listen(function(interaction: classes.TypesCommand)
if interaction.data.name ~= "slow" then
return
end
interaction:deferAsync():await()
-- ... do slow work ...
interaction:editResponseAsync(
builders.message.message.new()
:setContent("Done!")
:build()
):await()
end)
Full script
local discord = require("@self/../luau_packages/discord")
local classes = require("@self/../luau_packages/classes")
local builders = require("@self/../luau_packages/builders")
local env = require("@self/../.env")
local pingCommand = builders.interaction.interaction.new()
:setName("ping")
:setDescription("Replies with Pong!")
:setType("ChatInput")
:addIntegrationType("GuildInstall")
:addContext("Guild")
:build()
local bot = discord.bot.new({
token = env.DISCORD_BOT_TOKEN,
intents = builders.intents.new({ "Guilds" }):build(),
reconnect = true,
})
bot.onAllShardsReady:listenOnce(function()
local result = bot.application:createSlashCommandAsync(pingCommand):await()
if result:isErr() then
warn("Failed to register command:", result:unwrapErr())
return
end
print("Registered command:", result:unwrapOk().name)
end)
bot.onCommandInteraction:listen(function(interaction: classes.TypesCommand)
if interaction.data.name ~= "ping" then
return
end
interaction:messageAsync(
builders.message.message.new()
:setContent("Pong!")
:build()
):await()
end)
bot:connectAsync():await()
  • Bot - the discord.bot class, gateway connection and event emitters
  • Interaction builder - builders.interaction.interaction, constructs slash command definitions
  • Interaction Option builder - builders.interaction.option, adds typed parameters to commands
  • Message builder - builders.message.message, constructs response payloads
  • Intents builder - builders.intents, constructs the gateway intent bitfield
  • Futures - the FutureLike async primitive returned by async calls