---
title: "Discord Bot Slash Commands - Python & Node.js Guide | FPS.ms"
description: "Add slash commands to your Discord bot hosted on FPS.ms. Step-by-step guide for discord.py and discord.js with registration and handling."
url: https://fps.ms/docs/discord-bots/adding-slash-commands
---
# Adding slash commands

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) |

!!! tip "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:

1. Have your bot [installed and running on FPS.ms](https://fps.ms/docs/discord-bots/installation.md)
2. Added the `applications.commands` scope when [inviting your bot](https://fps.ms/docs/discord-bots/getting-your-bot-token.md)
3. Have your [bot token set up](https://fps.ms/docs/discord-bots/using-environment-variables.md) as an environment variable

!!! warning "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](https://discord.com/developers/applications) 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

```py title="app.py"
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

1. **`CommandTree`** — manages all your slash commands
2. **`@bot.tree.command()`** — registers a new slash command with a name and description
3. **`@app_commands.describe()`** — adds descriptions to command parameters
4. **`setup_hook()`** — syncs commands with Discord when the bot starts
5. **`interaction.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:

```js title="deploy-commands.js"
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:

```bash
node deploy-commands.js
```

!!! info "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](https://fps.ms/docs/discord-bots/using-environment-variables.md) for details."

### Step 2: Handle commands

```js title="index.js"
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**:

```py
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`:

```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](https://fps.ms/docs/discord-bots/troubleshooting.md).

## Next steps

- [Install your bot](https://fps.ms/docs/discord-bots/installation.md) — full setup for Python and Node.js
- [Edit your code](https://fps.ms/docs/discord-bots/editing-code.md) — update files via SFTP or VS Code
- [Set up environment variables](https://fps.ms/docs/discord-bots/using-environment-variables.md) — manage tokens and config securely
- [Create a schedule](https://fps.ms/docs/getting-started/creating-schedules.md) — set up automatic restarts

---

[FPS.ms](https://fps.ms/index.html.md) · [All pages](https://fps.ms/llms.txt) · [Documentation](https://fps.ms/docs/llms.txt)
