How to Deploy Discord Bot Globally vs Per-Server With Sync Decorator
🔍 WiseChecker

How to Deploy Discord Bot Globally vs Per-Server With Sync Decorator

Discord bot developers often need to decide whether slash commands should be available everywhere or only inside specific servers. The global approach registers commands for all servers that have the bot, while the per-server method limits commands to a single guild. The @app_commands.guilds() sync decorator in discord.py controls this behavior. This article explains the difference between global and per-server command deployment and how to use the sync decorator correctly.

Key Takeaways: Global vs Per-Server Discord Bot Commands

  • @app_commands.guilds() decorator: Restricts slash commands to one or more specific servers for instant testing and reduced propagation delay.
  • Global command registration: Makes commands available to all servers but can take up to one hour to propagate after changes.
  • Sync command (tree.sync()): Manually pushes command definitions to Discord and must be called after adding or modifying commands.

ADVERTISEMENT

Global vs Per-Server Command Deployment in Discord Bots

Discord slash commands are registered through the bot’s command tree. When you use tree.sync(), the bot sends its current command definitions to Discord’s API. Discord then stores these commands as either global commands or guild-specific commands.

Global commands are visible in every server that has the bot. Discord caches them aggressively, so changes can take up to one hour to appear. This delay makes global deployment unsuitable during development when you need to test command changes quickly.

Per-server commands are registered only on a specific guild ID. Discord updates them almost instantly — usually within a few seconds. Developers use this method in a single test server during development, then switch to global commands when the bot is ready for production.

How the @app_commands.guilds() Decorator Works

The @app_commands.guilds() decorator accepts one or more Discord guild IDs. When you apply it to a command, that command is registered only on those servers. If you remove the decorator and sync again, the command becomes global. The decorator does not affect the command’s functionality — it only controls where Discord stores the command definition.

You can mix global and per-server commands in the same bot. Commands without the decorator are global. Commands with the decorator are scoped to the listed guilds. This lets you keep some commands private for testing while others are publicly available.

Steps to Deploy Commands Globally and Per-Server

  1. Set Up Your Bot Project
    Create a Python file and import discord and app_commands. Initialize the bot with discord.Client and a command tree. Ensure you have a bot token from the Discord Developer Portal.
  2. Define a Global Command Without the Decorator
    Use @app_commands.command() to create a slash command. Do not add @app_commands.guilds(). Example: @app_commands.command(name="hello", description="Say hello"). This command will be global after sync.
  3. Define a Per-Server Command With the Decorator
    Apply @app_commands.guilds() above the command decorator. Pass the guild ID as an integer. Example: @app_commands.guilds(discord.Object(id=123456789012345678)). This command will appear only in that server.
  4. Sync the Command Tree
    Call await tree.sync() inside the on_ready event or via a dedicated sync command. For global commands, use await tree.sync(). For per-server commands, pass the guild object: await tree.sync(guild=discord.Object(id=123456789012345678)).
  5. Test the Commands in Discord
    Type /hello in the test server. The global command may not appear for up to an hour. The per-server command should appear immediately. If not, wait a few seconds and try again.
  6. Switch From Per-Server to Global for Production
    Remove the @app_commands.guilds() decorator from all commands. Call await tree.sync() without a guild argument. The commands will now be global. Note that global propagation takes up to one hour.

ADVERTISEMENT

Common Mistakes When Using the Sync Decorator

Commands Not Appearing After Sync

If commands do not show up after syncing, check the guild ID. The ID must be an integer, not a string. Also verify that the bot has the applications.commands scope enabled in the Discord Developer Portal. Without this scope, the bot cannot register slash commands.

Global Commands Still Visible After Switching to Per-Server

If you previously deployed a command globally and then add a @app_commands.guilds() decorator, the old global version may remain cached for up to an hour. To remove it immediately, call await tree.clear_commands(guild=None) and then sync. This deletes all global commands and lets the per-server version take over.

Sync Overwrites All Commands

Calling tree.sync() replaces all existing commands with the current definitions. If you accidentally omit a command from your code, syncing will delete it from Discord. Always keep a backup of your command definitions or use a staging server for testing.

Item Global Deployment Per-Server Deployment
Propagation speed Up to 1 hour Seconds
Visibility All servers with the bot Only specified guilds
Use case Production release Development and testing
Decorator required None @app_commands.guilds()
Sync call tree.sync() tree.sync(guild=Object(id))

Use global deployment for public bots that need commands in every server. Use per-server deployment during development to test changes immediately. After testing, remove the decorator and sync globally for production. Always sync after adding or modifying commands to ensure Discord has the latest definitions.

ADVERTISEMENT