Host a discord.js bot

Deploy the discord.js starter, paste in your token, and go from an empty server to a bot answering /ping — then learn exactly how the code works and add commands of your own.

Skip the setup This guide has a one-click starter template that installs everything below onto your server.

This guide takes you from an empty server to a bot replying to /ping in your Discord, using discord.js — the most popular library for building bots in JavaScript. You'll deploy a working starter first, then take it apart so you understand every line, then make it yours.

At a glance
You need a bot token from Your first Discord bot, and a Falix server running the Node.js application
Plan free or premium — free runs while your session timer has time left, premium keeps it up 24/7
Time about fifteen minutes

No server yet? See Create your first app server.

1. Deploy the starter

Use the template on this page. It writes index.js, package.json, .env, and a couple of helper files onto your server, overwriting only files with those names. If the server is currently running a different application, deploying switches it to Node.js first — that reinstalls the server and wipes its files, and the panel warns you before it does. On a fresh or already-Node server, nothing else is disturbed.

2. Paste in your token

Open the File Manager and edit .env. You'll see:

DISCORD_TOKEN=YOUR_TOKEN_HERE

Replace YOUR_TOKEN_HERE with the token you copied from the Developer Portal, save, and close. (More in Environment variables & secrets.)

💡 Tip: The .env file keeps your token out of your code and out of Git — never paste it directly into index.js.

3. Start it

Press Start on the Console page. On the first run the console shows npm install fetching discord.js and dotenv, then:

Listening as YourBot#0000

That line is your success signal. A bot makes only outbound connections to Discord, so there's no port to open; SERVER_PORT doesn't matter here.

🎯 Good to know: The word Listening is how the Node.js application flips your server's status to online — so your bot going live and the panel showing green are the same event.

4. Try it

In a channel of the server you invited the bot to, type /ping. It replies with the round-trip latency. If /ping doesn't appear in the command list yet, wait a few minutes — global slash commands can take a little while to register the very first time — then try again.

Want the bot in a second server? The invite URL you built in the Developer Portal isn't single-use — open it again and pick a different server (any where you have Manage Server). One running bot serves every server it's in; there's nothing to redeploy.

How it works

Here's the whole index.js the template deployed:

require('dotenv').config();
const { Client, GatewayIntentBits, Events } = require('discord.js');

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once(Events.ClientReady, async (c) => {
  await c.application.commands.set([
    { name: 'ping', description: 'Check that the bot is alive' },
  ]);
  console.log(`Listening as ${c.user.tag}`);
});

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand()) return;
  if (interaction.commandName === 'ping') {
    await interaction.reply(`Pong! ${client.ws.ping} ms`);
  }
});

client.login(process.env.DISCORD_TOKEN);

Five moving parts:

  • require('dotenv').config() reads the .env file and loads DISCORD_TOKEN into process.env so the code can use it without hard-coding the secret.
  • IntentsGatewayIntentBits.Guilds is all a slash-command bot needs. You add more intents only when your code handles more kinds of events, and privileged ones (like Message Content) must also be switched on in the Developer Portal.
  • ClientReady fires once, after login succeeds. It calls application.commands.set([...]) to register the bot's slash commands with Discord — that's what makes /ping show up when someone types /.
  • InteractionCreate fires whenever someone runs a command. The handler checks it's a slash command, matches on commandName, and replies.
  • client.login(process.env.DISCORD_TOKEN) connects using the token from .env. This is the call that either succeeds (Listening as …) or fails on a bad token.

Make it yours: add a second command

Slash commands live in two places, and adding one means editing both. Say you want /roll.

First, register it in the ClientReady handler by adding a line to the array:

await c.application.commands.set([
  { name: 'ping', description: 'Check that the bot is alive' },
  { name: 'roll', description: 'Roll a six-sided die' },
]);

Then answer it by adding a branch to InteractionCreate:

if (interaction.commandName === 'roll') {
  const result = Math.floor(Math.random() * 6) + 1;
  await interaction.reply(`🎲 You rolled a ${result}`);
}

Save and restart. After the usual first-time delay, /roll appears alongside /ping. Every new command follows this exact shape: describe it in the set([...]) list, handle it in InteractionCreate.

Adding packages

Reach for a library through the Packages page in your server menu: type the name into the Install package panel, press Install, and your package.json is updated for you; restart so your bot loads it. Editing package.json by hand works too (it installs on every start), but the Packages page is the easy path and flags outdated or insecure dependencies.

Troubleshooting

  • TokenInvalid in the console — the token in .env is wrong or was reset. Copy a fresh one from the Developer Portal (resetting invalidates the old) and paste it in again. See Bot appears offline.
  • Used disallowed intents — your code requests a privileged intent that isn't enabled. Toggle it on the Bot page in the Developer Portal, or remove it from the intents array if you don't need it.
  • /ping never appears — global commands lag on first registration; give it a few minutes. Still missing? Re-invite the bot with the applications.commands scope included.
  • Bot is online but ignores commands — that's the InteractionCreate handler. Make sure the listener is still there and that commandName matches the name you registered exactly.
  • Online but misbehaving another way — when the green dot is on but a command throws or does nothing, the answer is in the Console: an error and stack trace print there, below the Listening as … line, the moment your handler fails. Read it, fix the code, and restart.

Next steps

Was this guide helpful?