Creating commands

TIP

This page is a follow-up and bases its code on the previous page.

User used /ping
Guide Bot Bot 09/26/2021
Pong!

Discord allows developers to register slash commandsopen in new window, which provide users a first-class way of interacting directly with your application. Before being able to reply to a command, you must first register it.

Registering commands

This section will cover only the bare minimum to get you started, but you can refer to our in-depth page on registering slash commands for further details. It covers guild commands, global commands, options, option types, and choices.

Command deployment script

Create a deploy-commands.js file in your project directory. This file will be used to register and update the slash commands for your bot application.

You'll need to install @discordjs/buildersopen in new window, @discordjs/restopen in new window, and discord-api-typesopen in new window.

npm install @discordjs/builders @discordjs/rest discord-api-types
yarn add @discordjs/builders @discordjs/rest discord-api-types
pnpm add @discordjs/builders @discordjs/rest discord-api-types

Below is a deployment script you can use. Focus on these variables:

  • clientId: Your client's id
  • guildId: Your development server's id
  • commands: An array of commands to register. The slash command builder from @discordjs/builders is used to build the data for your commands

TIP

In order to get your client and guild ids, open Discord and go to your settings. On the "Advanced" page, turn on "Developer Mode". This will enable a "Copy ID" button in the context menu when you right-click on a server icon, a user's profile, etc.

const { SlashCommandBuilder } = require('@discordjs/builders');
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const { clientId, guildId, token } = require('./config.json');

const commands = [
	new SlashCommandBuilder().setName('ping').setDescription('Replies with pong!'),
	new SlashCommandBuilder().setName('server').setDescription('Replies with server info!'),
	new SlashCommandBuilder().setName('user').setDescription('Replies with user info!'),
]
	.map(command => command.toJSON());

const rest = new REST({ version: '9' }).setToken(token);

rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
	.then(() => console.log('Successfully registered application commands.'))
	.catch(console.error);



 

 
 
 
 
 
 






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
	"clientId": "123456789012345678",
	"guildId": "876543210987654321",
	"token": "your-token-goes-here"
}

 
 


1
2
3
4
5

Once you fill in these values, run node deploy-commands.js in your project directory to register your commands to a single guild. It's also possible to register commands globally.

TIP

You only need to run node deploy-commands.js once. You should only run it again if you add or edit existing commands.

Replying to commands

Once you've registered your commands, you can listen for interactions via Client#event:interactionCreateopen in new window in your index.js file.

You should first check if an interation is a command via .isCommand()open in new window, and then check the .commandNameopen in new window property to know which command it is. You can respond to interactions with .reply()open in new window.

client.once('ready', () => {
	console.log('Ready!');
});

client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;

	const { commandName } = interaction;

	if (commandName === 'ping') {
		await interaction.reply('Pong!');
	} else if (commandName === 'server') {
		await interaction.reply('Server info.');
	} else if (commandName === 'user') {
		await interaction.reply('User info.');
	}
});

client.login(token);




 
 
 
 
 
 
 
 
 
 
 
 
 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Server info command

Note that servers are referred to as "guilds" in the Discord API and discord.js library. interaction.guild refers to the guild the interaction was sent in (a Guildopen in new window instance), which exposes properties such as .name or .memberCount.

client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;

	const { commandName } = interaction;

	if (commandName === 'ping') {
		await interaction.reply('Pong!');
	} else if (commandName === 'server') {
		await interaction.reply(`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`);
	} else if (commandName === 'user') {
		await interaction.reply('User info.');
	}
});








 




1
2
3
4
5
6
7
8
9
10
11
12
13
User used /server
Guide Bot Bot 09/26/2021
Server name: Discord.js Guide
Total members: 2

You could also display the date the server was created, or the server's verification level. You would do those in the same manner–use interaction.guild.createdAt or interaction.guild.verificationLevel, respectively.

TIP

Refer to the Guildopen in new window documentation for a list of all the available properties and methods!

User info command

A "user" refers to a Discord user. interaction.user refers to the user the interaction was sent by (a Useropen in new window instance), which exposes properties such as .tag or .id.

client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;

	const { commandName } = interaction;

	if (commandName === 'ping') {
		await interaction.reply('Pong!');
	} else if (commandName === 'server') {
		await interaction.reply(`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`);
	} else if (commandName === 'user') {
		await interaction.reply(`Your tag: ${interaction.user.tag}\nYour id: ${interaction.user.id}`);
	}
});










 


1
2
3
4
5
6
7
8
9
10
11
12
13
User used /user
Guide Bot Bot 09/26/2021
Your tag: User#0001
Your id: 123456789012345678

TIP

Refer to the Useropen in new window documentation for a list of all the available properties and methods!

And there you have it!

The problem with if/else if

If you don't plan on making more than a couple commands, then using an if/else if chain is fine; however, this isn't always the case. Using a giant if/else if chain will only hinder your development process in the long run.

Here's a small list of reasons why you shouldn't do so:

  • Takes longer to find a piece of code you want;
  • Easier to fall victim to spaghetti codeopen in new window;
  • Difficult to maintain as it grows;
  • Difficult to debug;
  • Difficult to organize;
  • General bad practice.

Next, we'll be diving into something called a "command handler"–code that makes handling commands easier and much more efficient. This allows you to move your commands into individual files.

Resulting code

If you want to compare your code to the code we've constructed so far, you can review it over on the GitHub repository here open in new window.