Your Discord Slash Commands Aren't Showing Up — Check These in Order
If your bot deploys cleanly and its slash commands don't appear in Discord, the cause is almost never your hosting — the registration call succeeded or it didn't, and the answer is usually one of three things. Your invite link is missing the applications.commands scope, so the commands have nowhere to appear. You registered globally and expected guild-command behaviour, where only guild commands "update instantly." Or your registration call never actually ran, which the logs will tell you in seconds. There's also a fourth thing worth knowing before it bites: registering commands on every startup runs into a daily limit, and a crash-looping bot can burn through it fast.
1. Check the invite scope first
This is the one that wastes the most time, because everything in your code is correct and nothing works.
For commands to exist in a server, per Discord's documentation, "your app must be authorized with the applications.commands scope" (Discord docs). The scope "can be used independently, but is also automatically included with the bot scope" — so a modern invite usually has it. An older invite link, or one hand-built with only bot, may not.
The fix is not subtle: re-invite the bot with a URL that includes both scopes. You don't need to kick it first; re-authorising with the added scope is enough.
Symptom that points here: your registration API call returns success, and the commands still don't appear anywhere in that server.
2. Global or guild? They behave differently
Guild commands are "specific to the guild you specify when making them" and update instantly. Global commands are "available for every guild that adds your app" and don't.
Discord's current behaviour on global commands is worth stating precisely, because a lot of advice on this is out of date. Rather than a simple fixed delay, there's "inherent read-repair functionality": if you update a global command and "a user tries to use that command before it has updated for them, Discord will do an internal version check and reject the command." So a stale client gets corrected rather than silently running the wrong thing — but you can still see a gap between registering and seeing.
Practical rule:
- While developing, register to one test guild. Instant feedback, no waiting, no ambiguity about whether it worked.
- Register globally when you ship. Accept that it isn't immediate.
Registering globally and then refreshing Discord for ten minutes wondering what's broken is the single most common version of this problem.
3. Did the registration actually run?
Obvious, and worth thirty seconds before you go deeper. Registration is an API call your code makes — it can be skipped, throw, or never be reached.
Check the logs for the response. If your code doesn't log the outcome, add it now:
synced = await tree.sync(guild=guild)
print(f"registered {len(synced)} commands", flush=True)
Note flush=True — Python buffers stdout when it isn't a terminal, and a missing log line will have you debugging the wrong thing entirely.
Common ways this step silently doesn't happen:
- The sync runs in an
on_readyhandler that throws before reaching it. - The bot crashes before it gets there — check for a repeating exit line.
- The sync is behind a condition (
if DEBUG:) that isn't true in production.
4. Don't register on every startup
Here's the platform-specific part, and it's the one people don't see coming.
Discord's limit is explicit: "There is a global rate limit of 200 application command creates per day, per guild."
Two hundred is plenty for deliberate registration and not much at all for automatic registration. Your process restarts more often than you think — every redeploy, every configuration change, and, critically, every crash in a crash loop. At a five-second restart interval, a bot that syncs commands on boot reaches 200 in about 17 minutes.
Then command registration starts failing, on top of whatever was making it crash.
Better patterns, in order:
- Register when commands change, from a one-off script or a manual command you run yourself. Command definitions change far less often than your code deploys.
- If you must sync on boot, gate it. A
SYNC_COMMANDS=trueenvironment variable you flip on for one deploy and back off again works fine. - Never sync unconditionally in a handler that runs on reconnect. Reconnects are normal and frequent.
5. Bulk overwrite replaces everything
Worth knowing because it produces "my commands disappeared" rather than "my commands never appeared".
The bulk overwrite endpoint "takes a list of application commands, overwriting the existing command list", and it does so for "all types of application commands: slash commands, user commands, and message commands."
So if two code paths each bulk-register their own subset, the second one wipes the first. Same if you have a staging bot that registers to the same guild with the same application — the last one to sync wins. Keep a single source of truth for your command list, and register the whole set at once.
A quick diagnosis path
- Do the commands appear in any server? No → scope or registration. Yes → it's guild-specific.
- Does your log show a successful sync with a command count? No → the call didn't run.
- Did you register globally? Give it time, and test against a guild registration meanwhile.
- Did commands appear and then vanish? Something bulk-overwrote them.
- Is registration now returning errors? Check whether you've been syncing on every restart.
FAQ
Why don't my slash commands appear after deploying?
Most often the bot was invited without the applications.commands scope, or the commands were registered globally rather than to a guild. Check the logs to confirm registration ran.
How long do global commands take to appear?
Not instantly. Discord version-checks stale invocations and repairs them, but there's a gap between registering and seeing. Guild commands update instantly — use one for development.
Do I need to re-invite my bot?
If the original invite lacked applications.commands, yes. Re-authorising with the scope added is enough; you don't have to remove the bot first.
Should I sync commands on every startup?
No. There's a limit of 200 command creates per day per guild, and a restarting bot burns through it. Register when your commands change.
My commands disappeared — what happened?
Something bulk-overwrote the list. That endpoint replaces the whole command set, so two registration paths will clobber each other.
Could my hosting be the problem?
Rarely. Registration is an ordinary API call. What hosting affects is how often your process restarts, which matters only if you register on boot.
Wrapping up
Slash-command problems feel like deployment problems and almost never are — the same code registering the same commands from your laptop would behave identically. Work down the list: scope, then global-versus-guild, then whether the call ran at all. The one genuinely hosting-adjacent trap is syncing on startup, which is fine until the day your bot restarts in a loop and quietly exhausts a limit you didn't know existed.