Subcommands & Groups
Discord supports grouping related actions under a single top-level command using subcommands and subcommand groups. The framework resolves which handler to call automatically based on the interaction data.
Subcommands
Section titled “Subcommands”Add SubCommand options to the interaction builder, then provide a matching subcommands table on the definition. Each key is a subcommand name and each value is a SubcommandDefinition.
local builders = require("../../luau_packages/builders")local classes = require("../../luau_packages/classes")
return { command = builders.interaction.interaction.new() :setName("reminder") :setDescription("Manage reminders") :addIntegrationType("GuildInstall") :addContext("Guild") :addOption( builders.interaction.option.new() :setType("SubCommand") :setName("set") :setDescription("Set a new reminder") :build() ) :addOption( builders.interaction.option.new() :setType("SubCommand") :setName("clear") :setDescription("Clear all reminders") :build() ) :build(),
execute = function(interaction: classes.TypesCommand) -- fallback if no subcommand matched interaction:messageAsync({ content = "Unknown subcommand.", flags = 64 }):await() end,
subcommands = { set = { execute = function(interaction: classes.TypesCommand) interaction:messageAsync({ content = "Reminder set!" }):await() end, }, clear = { execute = function(interaction: classes.TypesCommand) interaction:messageAsync({ content = "Reminders cleared." }):await() end, }, },}Subcommand groups
Section titled “Subcommand groups”For a second level of nesting, use SubCommandGroup options. The subcommands table then has a group name at the top level, and subcommand names nested inside.
return { command = builders.interaction.interaction.new() :setName("config") :setDescription("Bot configuration") :addIntegrationType("GuildInstall") :addContext("Guild") :addOption( builders.interaction.option.new() :setType("SubCommandGroup") :setName("logging") :setDescription("Logging settings") :addOption( builders.interaction.option.new() :setType("SubCommand") :setName("enable") :setDescription("Enable logging") :build() ) :addOption( builders.interaction.option.new() :setType("SubCommand") :setName("disable") :setDescription("Disable logging") :build() ) :build() ) :build(),
execute = function(interaction: classes.TypesCommand) interaction:messageAsync({ content = "Unknown subcommand.", flags = 64 }):await() end,
subcommands = { logging = { enable = { execute = function(interaction: classes.TypesCommand) interaction:messageAsync({ content = "Logging enabled." }):await() end, }, disable = { execute = function(interaction: classes.TypesCommand) interaction:messageAsync({ content = "Logging disabled." }):await() end, }, }, },}Per-subcommand guards and transforms
Section titled “Per-subcommand guards and transforms”SubcommandDefinition supports its own guards and transforms tables, which run in addition to any top-level ones on the parent command.
subcommands = { set = { guards = { function(interaction: classes.TypesCommand): boolean return interaction.guildId ~= nil end, },
transforms = { duration = function(value: any, interaction: classes.TypesCommand) return tonumber(value) or 60 end, },
execute = function(interaction: classes.TypesCommand) local duration = interaction:getTransformed("duration")
interaction:messageAsync({ content = `Reminder in {duration}s` }):await() end, },},References
Section titled “References”- Options & Transforms - defining options and transforms
- Guards & Permissions - restricting access per-subcommand