Learning objectives
After reading this article you will be able to:
- Build a discord.js bot that reads its token from an environment variable
- Register a slash command and test the bot locally
- Move the bot to a host and confirm it is online
A discord.js bot is a Node.js process that opens a connection to the Discord Gateway and reacts to events. The bot shows as online while that process is up and connected; when the process stops, the bot goes offline for everyone.
This guide takes you from an empty folder to a live bot, with complete discord.js v14 code using ES modules. If you have not created the Discord app yet, how to make your first Discord bot covers that part in more detail.
What do you need before you start?#
- A Node.js LTS release. The official discord.js guide recommends the current Active LTS of Node.js, and the official release schedule shows which version that is.
- An app in the Discord Developer Portal, with the bot created and its token copied.
- A test server where you are allowed to invite the bot.
The token is the bot's password. See Discord bot token: where to get it and how to store it. From here on it always comes from an environment variable called DISCORD_TOKEN.
How do you set up the project?#
Create the folder and install the library:
mkdir my-bot && cd my-bot
npm init -y
npm install discord.jsIn package.json, add "type": "module" so you can use import. Then create a .env file (and add .env to .gitignore):
DISCORD_TOKEN=paste_the_token_here
CLIENT_ID=your_application_id
GUILD_ID=your_test_server_idNode.js can load this file itself with the --env-file flag, no extra package needed. It has existed since version 20.6 and is stable from 24.10, according to the Node.js documentation.
How do you write the bot code?#
Create index.js. The bot below uses only the Guilds intent, which is enough for slash commands, and answers a /ping command:
import { Client, Events, GatewayIntentBits } from "discord.js";
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, (readyClient) => {
console.log(`Online as ${readyClient.user.tag}`);
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "ping") {
await interaction.reply("Pong!");
}
});
client.login(process.env.DISCORD_TOKEN);If the bot has to read message text, you will need to enable the privileged MessageContent intent in the Portal and in the code. That is the most common stumbling block for people moving from prefix commands, and it is covered in Discord bot intents error.
How do you register the slash command?#
Starting the bot does not create the command. You must send it to the Discord API once, and again whenever its definition changes. Create deploy-commands.js:
import { REST, Routes, SlashCommandBuilder } from "discord.js";
const commands = [
new SlashCommandBuilder().setName("ping").setDescription("Replies with Pong!"),
].map((command) => command.toJSON());
const rest = new REST().setToken(process.env.DISCORD_TOKEN);
await rest.put(
Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
{ body: commands },
);
console.log(`${commands.length} command(s) registered.`);Registering per server is the recommended way to test. Once the commands are ready, switch the route to Routes.applicationCommands(process.env.CLIENT_ID) so they apply to every server the bot is in, as the discord.js guide explains.
For the invite to work, generate the URL under OAuth2 in the Portal with the bot and applications.commands scopes.
How do you test before hosting?#
Register the command and start the bot:
node --env-file=.env deploy-commands.js
node --env-file=.env index.jsThe terminal should print Online as BotName. In your server, type /ping and check that the reply arrives. If the bot is online but the command is missing, go back to the registration step. If the bot never comes online, the token is wrong or was reset.
Where should you host the bot?#
Your own computer is fine for development, but the bot goes down when the machine shuts off. To stay up, the process has to run on another machine that is always on:
- VPS: you install Node.js, set up a supervisor such as pm2 or systemd, and handle updates and the firewall. The full walkthrough is in how to keep a Discord bot online 24/7.
- Bot hosting platform: you upload the code and set the variables; the Node.js environment already exists. It is usually faster to set up.
To estimate your bot's memory, see how much RAM a Discord bot needs, and to compare prices, how much it costs to host a Discord bot.
What errors show up when hosting?#
Error [TokenInvalid]: An invalid token was provided.: theDISCORD_TOKENvariable never reached the process. Your local.envdoes not exist on the host unless you upload it, so set the variable in the host's panel.Used disallowed intents: the code asks for a privileged intent that is not enabled in the Portal.- The process exits with no error: the main file is wrong, or an unhandled exception killed Node.js. Read the logs and see why your Discord bot goes offline.
- A command appears twice: the same command was registered per server and globally. Register it through only one of the two.
How to do this on Square Cloud#
On Square Cloud, the bot runs in an isolated, always-on container, with automatic restart (on by default for dashboard deploys) when the process exits with an error. You deploy it yourself by ZIP upload in the dashboard, the CLI, GitHub or the VS Code extension.
- Zip the project (
index.js,package.json, withoutnode_modules) and upload it in the dashboard; at start, the platform runsnpm install. Thesquarecloud.appconfig file is optional: the dashboard generates it with the runtime, memory and main file, or you write it at the project root. - Pick Node.js as the runtime and
index.jsas the main file. Each background application, such as a bot, uses at least 256 MB from the plan's RAM pool. - Set
DISCORD_TOKENin the application's environment variables. The change applies on the next restart, with no rebuild. - Follow the real-time logs in the dashboard, the CLI or VS Code and confirm the
Online as ...line.
Plans are paid: Hobby, at R$12.49 per month, includes 1 GB of RAM and 1 vCPU. See the details in Discord bot hosting on Square Cloud.
Bot hosting
Keep your bot online 24/7 with automatic restarts
FAQs
Which Node.js version should I use with discord.js?
Use the current Active LTS of Node.js, as the official discord.js guide recommends. It meets the minimum discord.js v14 declares on npm and gets fixes for the longest.
Do I need the MessageContent intent for my bot to work?
Not for slash commands. The Guilds intent is enough. MessageContent is privileged and is only needed if the bot must read the text of regular messages.
Can I put the token directly in the code?
No. Anyone who sees the code can control the bot. Read the token from an environment variable and, if it leaks, generate a new one in the Developer Portal.
Why does my slash command not show up in Discord?
The command has to be registered with the Discord API, which is a separate step from starting the bot. Run the registration script and check that the bot was invited with the applications.commands scope.
More in Bots
See all 33 articles- How much does it cost to host a Discord bot?The cost of hosting a Discord bot depends on RAM, uptime, database and outside services. Learn how to estimate your own bill and where the money goes.
- Running a bot on your phone or PC vs hosting itA bot on your PC or phone (Termux) goes offline when the device shuts down, sleeps or loses its network. Compare the three options and when each one fits.
- Why your Discord bot keeps going offline (and how to fix it)A Discord bot goes offline when the process dies, the token is invalid, an intent is disabled or memory runs out. Learn to diagnose each cause and fix it.
- How to host a Telegram bot 24/7To keep a Telegram bot online 24/7, run its process on an always-on server using long polling or a webhook. See working code and the common errors.