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 special approval
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 Space-Node for reliable 24/7 availability. Slash commands only work when your bot is online - consistent uptime ensures your commands are always responsive.
