Discord bots using slash commands often need to organize many related actions. Without a clear structure, users face a flat list of dozens of commands. Subcommand groups solve this by grouping related commands into menus. Three-level nesting lets you create a hierarchy like /mod warn add or /admin config log set. This article explains the exact syntax and steps to implement three-level subcommand groups in your Discord bot using discord.py.
Key Takeaways: Building Three-Level Bot Command Groups
discord.app_commands.Groupclass: Creates a top-level command group that can hold subcommands or child groups.- Nested group instances: Assign a
Groupobject as theparentof another group to achieve three-level nesting. - Decorator chain
@group.command: Registers a subcommand under a group; repeat the pattern for deeper levels.
Understanding Three-Level Nesting in Discord Slash Commands
Discord supports up to three levels of nesting for slash command groups. The structure is: top-level command, then subcommand group, then subcommand. A bot command like /settings notifications dm on follows this pattern. settings is the top-level command, notifications is a subcommand group, and dm is a subcommand. The final on is a parameter of the subcommand.
The discord.py library implements this through the discord.app_commands.Group class. Each group can contain subcommands or child groups. The library enforces the three-level limit. You cannot nest deeper than this.
Before you start, you need a working Discord bot with the discord.py library version 2.0 or later. Your bot must have the applications.commands scope enabled in the Developer Portal. The bot also needs the message_content intent if you use prefix commands alongside slash commands, but slash commands themselves do not require it.
The Group Class Structure
The discord.app_commands.Group class accepts these key parameters:
- name: The command name users type after the slash.
- description: Shown in the command picker.
- parent: Another Group object this group belongs under.
- guild_ids: Optional list of guild IDs to restrict the command.
When you set a parent, the child group appears as a nested option under the parent command. The parent group itself does not execute any code. Only the leaf subcommands contain the actual callback function.
Steps to Create a Three-Level Subcommand Group
The following steps use a moderation bot example. The final command structure will be /mod user warn, /mod user ban, and /mod user kick. The top-level group is mod, the second level is user, and the third level is the actual subcommand.
- Import the Group class
Add this import at the top of your bot file:from discord.app_commands import Group - Create the top-level group
Define aGroupinstance without a parent:mod_group = Group(name="mod", description="Moderation commands") - Create the second-level group
Define a secondGroupand pass the top-level group as its parent:user_group = Group(name="user", description="User moderation actions", parent=mod_group) - Create the third-level subcommand
Use the@user_group.commanddecorator to register a subcommand underuser_group:@user_group.command(name="warn", description="Warn a user")async def warn(interaction: discord.Interaction, member: discord.Member, reason: str):await interaction.response.send_message(f"Warned {member.mention} for {reason}") - Add more subcommands under the same group
Repeat the decorator pattern forbanandkick:@user_group.command(name="ban", description="Ban a user")async def ban(interaction: discord.Interaction, member: discord.Member, reason: str):await interaction.response.send_message(f"Banned {member.mention}")@user_group.command(name="kick", description="Kick a user")async def kick(interaction: discord.Interaction, member: discord.Member, reason: str):await interaction.response.send_message(f"Kicked {member.mention}") - Register the top-level group with the bot
Add this line inside your bot setup oron_readyevent:await bot.tree.add_command(mod_group)
If you useguild_ids, pass them when creating the group or usebot.tree.add_command(mod_group, guild=discord.Object(id=GUILD_ID)) - Sync the command tree
Callawait bot.tree.sync()after adding commands. For global commands, this can take up to an hour. For guild-specific commands, syncing is instant.
Common Mistakes and Limitations
Three-level nesting is the maximum
Discord does not allow four or more levels. If you try to set a parent on a group that already has a grandparent, the library will raise an error. Plan your command hierarchy carefully.
Top-level groups cannot have their own callback
A Group object does not execute a function when invoked. Only leaf subcommands have callbacks. If a user types /mod alone, Discord shows the available subcommand groups and subcommands. No code runs.
Group names must be unique within the same scope
You cannot have two groups named user under the same parent. The combination of parent name and group name must be unique. Different parent groups can have child groups with the same name.
Subcommands cannot have the same name as their group
A subcommand name must differ from the group name. For example, under user_group you cannot have a subcommand named user. Discord will reject the command registration.
Guild-specific commands sync faster than global
Global commands take up to one hour to propagate. For testing, use guild_ids or pass a guild parameter to add_command. Remove the guild restriction before deploying to production.
Subcommand Group Structure: Top-Level vs Second-Level vs Third-Level
| Item | Top-Level Group | Second-Level Group | Third-Level Subcommand |
|---|---|---|---|
| Role | Container for related groups | Container for subcommands | Executable command |
| Has callback | No | No | Yes |
| Example usage | /mod |
/mod user |
/mod user warn |
| Nesting limit | Can hold groups only | Can hold subcommands only | Cannot hold anything |
| Discord display | Shows child groups | Shows subcommands | Shows parameters |
Now you can create a three-level subcommand group in your Discord bot using discord.py. Start with a top-level Group, attach a child group, and register subcommands under the child. Remember the three-level limit. Test with guild-specific syncing first. For advanced bots, consider using Group with default_permissions to restrict commands to moderators only.