How to make a slash commands bot with Discord.js V13
Tags: discord, djs, bot, tutorial
Published: 2021-09-04 14:14:17

So Discord has implemented a pretty big change in their API starting from early 2022 which will make message content a privileged intent and verified bots will have to request that intent additionally.

So I'm here to share how you can migrate your bot to slash commands entirely so that it doesn't stop working.

Before we get started, if you'd like to hang out with the community, you can join our Discord server here: [DevHQ](https://dsc.gg/devhq)

If you are here just for the resulting code, you can find out the repository here: [Repository](https://github.com/kb24x7/discordjs-v13-starter/)

[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template?template=https%3A%2F%2Fgithub.com%2Fkb24x7%2Fdiscordjs-v13-starter&envs=TOKEN%2CTEST_GUILD_ID&optionalEnvs=TEST_GUILD_ID&TOKENDesc=Your+Bot%27s+Token&TEST_GUILD_IDDesc=Your+development+server%27s+guild+ID%2C+only+add+this+if+your+bot+is+in+development&referralCode=7OsmmG)

Let's get started.

You have to invite your bot with an updated scope of application.commands which is required to register slash commands.

![Screen Shot 2021-09-04 at 7.24.58 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d97ucnpjvkpieur599hf.png)
 

First things first, its always recommended to use yarn since its much better than npm, so you can install that using:

```npm -g install yarn```

Let's make a new directory for our bot, cd it, and initialize it using:

```yarn init --yes```

Let's install Discord.js and some other dependencies,
```
yarn add discord.js @discordjs/rest discord-api-types/v9 @discordjs/builders
```

Time to create an index.js file, and import the following stuff:

```js
const fs = require('fs');
const {
	REST
} = require('@discordjs/rest');
const {
	Routes
} = require('discord-api-types/v9');
// Require the necessary discord.js classes
const {
	Client,
	Intents,
	Collection
} = require('discord.js');

// Create a new client instance
const client = new Client({
	intents: [Intents.FLAGS.GUILDS]
});
```

Now we have created a client instance which only uses the Guild intent required to respond for slash commands, it is much less memory intensive than processing every single message throughout Discord.

Now, we will create a dynamic command structure for our bot, so lets create a directory called commands and add this to the index.js file:

```js
// Loading commands from the commands folder
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
```

Now it's time for tokens, pushing tokens into GitHub is very not recommended so we have to use env files to store our tokens safely. 

```yarn add dotenv```

Create a .env file and add your token and your test guild / server id here, we'll talk about the test server later.

```
TOKEN=YOUR_TOKEN_HERE
TEST_GUILD_ID=YOUR_GUILD_ID_HERE
```

You can copy the Guild ID like this
![Screen Shot 2021-09-04 at 7.16.36 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct0z62z35bth2d23xpla.png)
 

Create a .gitignore file and add this to the file:
```
.env
```

Time to configure it in our index file:
```js
// Loading the token from .env file
const dotenv = require('dotenv');
dotenv.config();
const TOKEN = process.env['TOKEN'];
```

Now that we have finally gotten our token, it's time to talk about the Test Guild ID, so slash commands in Discord requires us to register it first, and we can't register it globally every time in development or we are gonna get rate-limited and potentially banned from accessing their API for some time.

We only need this in development, we don't need to do this when we are deploying our bot in production. So please don't add the Test Guild ID when you want your commands globally available. Now let's add the Guild ID to the index file:

```js
const TEST_GUILD_ID = process.env['TEST_GUILD_ID'];
```

It's time to register our commands now, we will make a condition that will automatically switch between global and development registration depending upon whether the Test Guild ID is available.

```js
const commands = [];

// Creating a collection for commands in client
client.commands = new Collection();

for (const file of commandFiles) {
	const command = require(`./commands/${file}`);
	commands.push(command.data.toJSON());
	client.commands.set(command.data.name, command);
}

// When the client is ready, this only runs once
client.once('ready', () => {
	console.log('Ready!');
	// Registering the commands in the client
	const CLIENT_ID = client.user.id;
	const rest = new REST({
		version: '9'
	}).setToken(TOKEN);
	(async () => {
		try {
			if (!TEST_GUILD_ID) {
				await rest.put(
					Routes.applicationCommands(CLIENT_ID), {
						body: commands
					},
				);
				console.log('Successfully registered application commands globally');
			} else {
				await rest.put(
					Routes.applicationGuildCommands(CLIENT_ID, TEST_GUILD_ID), {
						body: commands
					},
				);
				console.log('Successfully registered application commands for development guild');
			}
		} catch (error) {
			if (error) console.error(error);
		}
	})();
});
```

Now that we have registered our commands in Discord, it's time to listen and respond to them

```js
client.on('interactionCreate', async interaction => {
	if (!interaction.isCommand()) return;
	const command = client.commands.get(interaction.commandName);
	if (!command) return;
	try {
		await command.execute(interaction);
	} catch (error) {
		if (error) console.error(error);
		await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
	}
});
```

Finally for our index file, we need to log in to our bot

```js
// Login to Discord with your client's token
client.login(TOKEN);
```

We can now move into the commands sub-directory, and let's make a ping.js file with the following code:

```js
const { SlashCommandBuilder } = require('@discordjs/builders');

module.exports = {
	data: new SlashCommandBuilder()
		.setName('ping')
		.setDescription('Replies with pong'),
	async execute(interaction) {
		interaction.reply({ content: 'Pong' })
	}
};
```

We have now successfully created a working ping pong bot in Discord.js V13. Now you can create as many commands as you want for your bot by following the same format as the ping command. The code for embeds are same, and there are a lot of new features like buttons and select menus which we haven't talked about here. If you want to send an embed, you just need to do:

```js
interaction.reply({ embeds: [embed] })
```

Hope you like this *short* tutorial and you can follow me on Twitter [here](https://twitter.com/kb24x7)


### Free Deployment Platforms:
* [Railway](https://railway.app)
* [Qovery](https://www.qovery.com/)
* [OpeNode](https://www.openode.io/)
* [Heroku](https://heroku.com)


Hope to see you on the next one :)