
Slash commands replaced prefix commands as the standard interaction method. If your bot still relies on !command, it's time to modernize.
Why Slash Commands?
- Discoverability: Users type
/and see all available commands - Validation: Discord validates input types before your bot receives them
- Permissions: Server admins control command access through Discord's UI
- Mobile-friendly: Works properly on mobile Discord
- Required: Message content intent is now privileged (prefix commands need it switched on in the Developer Portal, and Discord's approval once more than 10,000 users can see the bot)
Registration
Global Commands
Available in all servers (up to 1 hour to propagate):
const { REST, Routes, SlashCommandBuilder } = require('discord.js');
const commands = [
new SlashCommandBuilder()
.setName('ping')
.setDescription('Check bot latency'),
new SlashCommandBuilder()
.setName('userinfo')
.setDescription('Get user information')
.addUserOption(option =>
option.setName('user')
.setDescription('Target user')
.setRequired(false))
];
const rest = new REST({ version: '10' }).setToken(TOKEN);
await rest.put(Routes.applicationCommands(CLIENT_ID), {
body: commands.map(c => c.toJSON())
});
Guild Commands
Available instantly in specific servers (for testing):
await rest.put(Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID), {
body: commands.map(c => c.toJSON())
});
Command Options
String Options
new SlashCommandBuilder()
.setName('echo')
.setDescription('Repeat a message')
.addStringOption(option =>
option.setName('message')
.setDescription('What to say')
.setRequired(true)
.setMaxLength(100))
Number Options
.addIntegerOption(option =>
option.setName('amount')
.setDescription('How many')
.setMinValue(1)
.setMaxValue(100))
Choice Options
.addStringOption(option =>
option.setName('color')
.setDescription('Pick a color')
.addChoices(
{ name: 'Red', value: 'red' },
{ name: 'Blue', value: 'blue' },
{ name: 'Green', value: 'green' }
))
Handling Commands
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
switch (interaction.commandName) {
case 'ping':
await interaction.reply({
content: `Pong! ${client.ws.ping}ms`,
ephemeral: true // Only visible to command user
});
break;
case 'userinfo':
const user = interaction.options.getUser('user') || interaction.user;
await interaction.reply({
embeds: [{
title: user.tag,
fields: [
{ name: 'ID', value: user.id },
{ name: 'Created', value: user.createdAt.toDateString() }
]
}]
});
break;
}
});
Subcommands
Group related commands:
new SlashCommandBuilder()
.setName('settings')
.setDescription('Server settings')
.addSubcommand(sub =>
sub.setName('view')
.setDescription('View current settings'))
.addSubcommand(sub =>
sub.setName('set')
.setDescription('Change a setting')
.addStringOption(opt =>
opt.setName('key').setDescription('Setting name').setRequired(true))
.addStringOption(opt =>
opt.setName('value').setDescription('New value').setRequired(true)))
Autocomplete
Dynamic suggestions as the user types:
client.on('interactionCreate', async interaction => {
if (interaction.isAutocomplete()) {
const focused = interaction.options.getFocused();
const choices = ['minecraft', 'rust', 'fivem', 'valheim'];
const filtered = choices.filter(c => c.startsWith(focused.toLowerCase()));
await interaction.respond(
filtered.map(choice => ({ name: choice, value: choice }))
);
}
});
Permissions
Default Permissions
new SlashCommandBuilder()
.setName('ban')
.setDescription('Ban a user')
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)
DM Permissions
new SlashCommandBuilder()
.setName('serverinfo')
.setDMPermission(false) // Only usable in servers
Deployment Tips
- Register global commands once (they persist until you update)
- Use guild commands during development (instant updates)
- Keep command descriptions clear and concise
- Use ephemeral replies for sensitive information
- Respond within 3 seconds or defer:
await interaction.deferReply(); // Buy time
// ... long operation ...
await interaction.editReply('Done!');
Host your bot on our Discord bot hosting for reliable 24/7 availability. Slash commands only work when your bot is online, so consistent uptime keeps your commands responsive.