Slash commands are the modern way for users to interact with Discord bots. When a user types / in a Discord channel, they see a list of available commands with descriptions and parameters. This guide shows you how to add slash commands to your bot hosted on FPS.ms.
Why use slash commands?
| Feature | Slash commands | Message-based commands |
|---|---|---|
| Discoverability | Users see all commands by typing / |
Users must know the prefix and command name |
| Permissions | Built-in Discord permission system | Must be coded manually |
| Parameters | Typed parameters with validation | Must parse text manually |
| Message Content intent | Not required | Required (privileged intent) |
Recommended for new bots
Discord recommends slash commands for all new bots. They don't require the Message Content privileged intent, making your bot easier to verify and approve.
Prerequisites
Before adding slash commands, make sure you:
- Have your bot installed and running on FPS.ms
- Added the
applications.commandsscope when inviting your bot - Have your bot token set up as an environment variable
Missing applications.commands scope?
If you didn't include applications.commands when inviting your bot, slash commands won't work. Re-invite the bot using the OAuth2 URL Generator in the Discord Developer Portal with both bot and applications.commands scopes selected.
Python (discord.py)
Discord.py uses a commands.Bot with a command tree to handle slash commands.
Basic slash command
import os
from dotenv import load_dotenv
import discord
from discord import app_commands
load_dotenv()
class MyBot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
async def setup_hook(self):
await self.tree.sync()
print(f'Synced {len(self.tree.get_commands())} commands')
bot = MyBot()
@bot.tree.command(name='ping', description='Check if the bot is online')
async def ping(interaction: discord.Interaction):
await interaction.response.send_message(f'Pong! Latency: {round(bot.latency * 1000)}ms')
@bot.tree.command(name='hello', description='Get a greeting from the bot')
@app_commands.describe(name='The name to greet')
async def hello(interaction: discord.Interaction, name: str = None):
if name:
await interaction.response.send_message(f'Hello, {name}!')
else:
await interaction.response.send_message(f'Hello, {interaction.user.display_name}!')
bot.run(os.environ['BOT_TOKEN'])
How it works
CommandTree— manages all your slash commands@bot.tree.command()— registers a new slash command with a name and description@app_commands.describe()— adds descriptions to command parameterssetup_hook()— syncs commands with Discord when the bot startsinteraction.response.send_message()— replies to the user
Node.js (discord.js)
Discord.js uses a two-step process: register commands via the REST API, then handle them in your bot code.
Step 1: Register commands
Create a separate script to register your commands with Discord:
require('dotenv').config();
const { REST, Routes, SlashCommandBuilder } = require('discord.js');
const commands = [
new SlashCommandBuilder()
.setName('ping')
.setDescription('Check if the bot is online'),
new SlashCommandBuilder()
.setName('hello')
.setDescription('Get a greeting from the bot')
.addStringOption(option =>
option.setName('name')
.setDescription('The name to greet')
.setRequired(false)),
].map(command => command.toJSON());
const rest = new REST().setToken(process.env.BOT_TOKEN);
(async () => {
try {
console.log('Registering slash commands...');
await rest.put(
Routes.applicationCommands(process.env.CLIENT_ID),
{ body: commands },
);
console.log('Slash commands registered!');
} catch (error) {
console.error(error);
}
})();
Run this script once to register your commands:
node deploy-commands.js
Set CLIENT_ID
Add CLIENT_ID=your-app-id to your .env file on FPS.ms. Find it in the Discord Developer Portal under your application's General Information page (called Application ID). See the environment variables guide for details.
Step 2: Handle commands
require('dotenv').config();
const { Client, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'ping') {
await interaction.reply(`Pong! Latency: ${Math.round(client.ws.ping)}ms`);
}
if (interaction.commandName === 'hello') {
const name = interaction.options.getString('name');
if (name) {
await interaction.reply(`Hello, ${name}!`);
} else {
await interaction.reply(`Hello, ${interaction.user.displayName}!`);
}
}
});
client.once(Events.ClientReady, readyClient => {
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
});
client.login(process.env.BOT_TOKEN);
Global vs guild commands
| Type | Registration time | Scope | Best for |
|---|---|---|---|
| Global | Up to 1 hour | All servers the bot is in | Production bots |
| Guild | Instant | One specific server | Development and testing |
For faster testing, register commands to a specific guild. In Python:
MY_GUILD = discord.Object(id=int(os.environ['GUILD_ID']))
async def setup_hook(self):
self.tree.copy_global_to(guild=MY_GUILD)
await self.tree.sync(guild=MY_GUILD)
In Node.js, change the Routes in deploy-commands.js:
// Global (slow, production)
Routes.applicationCommands(process.env.CLIENT_ID)
// Guild-specific (instant, development)
Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID)
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Commands not showing up | Not synced or registration delay | For global commands, wait up to 1 hour. For guild commands, check the guild ID. |
Missing Access error |
Bot missing applications.commands scope |
Re-invite the bot with the correct scopes |
Unknown interaction |
Bot took too long to respond (>3 seconds) | Use interaction.deferReply() for slow operations |
| Duplicate commands | Synced both global and guild copies | Remove guild commands if using global, or vice versa |
For more help, see our full troubleshooting guide.
Next steps
- Install your bot — full setup for Python and Node.js
- Edit your code — update files via SFTP or VS Code
- Set up environment variables — manage tokens and config securely
- Create a schedule — set up automatic restarts