How to Host a Node.js (discord.js) Bot on a VPS
Deploy a discord.js bot on a VPS from scratch: install Node.js, structure the project, register slash commands, secure the token, and run it with PM2.

discord.js is the most popular way to build Discord bots, and a VPS is the right place to run one in production. This guide takes a discord.js bot from a fresh server to a 24/7 deployment with PM2. For the language-agnostic overview, see how to host a Discord bot on a VPS 24/7.
Step 1: Install Node.js
Use the current LTS. On Ubuntu/Debian:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs git
node -v && npm -v
Step 2: Set up the project
If you're starting fresh:
mkdir my-bot && cd my-bot
npm init -y
npm install discord.js dotenv
Or clone your repo and npm install. Store your token in .env:
echo "DISCORD_TOKEN=your-bot-token-here" > .env
echo "CLIENT_ID=your-application-id" >> .env
echo "node_modules/\n.env" > .gitignore
chmod 600 .env

Step 3: A minimal discord.js bot
index.js using the modern gateway intents and a slash command handler:
require("dotenv").config();
const { Client, GatewayIntentBits, Events } = require("discord.js");
const client = new Client({
intents: [GatewayIntentBits.Guilds]
});
client.once(Events.ClientReady, (c) => {
console.log(`Logged in as ${c.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);
Step 4: Register slash commands
Slash commands must be registered with Discord's API. A deploy-commands.js script:
require("dotenv").config();
const { REST, Routes } = require("discord.js");
const commands = [
{ name: "ping", description: "Replies with Pong!" }
];
const rest = new REST({ version: "10" }).setToken(process.env.DISCORD_TOKEN);
(async () => {
await rest.put(
Routes.applicationCommands(process.env.CLIENT_ID),
{ body: commands }
);
console.log("Slash commands registered.");
})();
Run it once after any command change:
node deploy-commands.js
Step 5: Run it 24/7 with PM2
sudo npm install -g pm2
pm2 start index.js --name discord-bot
pm2 save
pm2 startup # run the sudo command it prints
The full PM2 workflow — logs, memory limits, auto-restart — is covered in how to keep a Discord bot online with PM2.
Step 6: Deploy updates
cd ~/my-bot
git pull
npm install
node deploy-commands.js # only if commands changed
pm2 restart discord-bot
Production tips
- Pin Node's version and keep discord.js updated for gateway compatibility.
- Enable only the intents you use — request privileged intents (like Message Content) in the Developer Portal only if needed.
- Never commit
.env— the.gitignoreabove prevents leaking your token. - Secure the server with SSH keys and a firewall — securing your first Linux VPS: 10 steps.
Prefer containers? See how to deploy a Discord bot with Docker. Node.js also powers a lot more than bots — our Node.js hosting page covers running full apps.
Structuring a bigger bot
A one-file bot is fine to start, but growing bots benefit from a command/event folder structure:
my-bot/
index.js
deploy-commands.js
commands/
ping.js
userinfo.js
events/
ready.js
interactionCreate.js
index.js loops over commands/ and events/, registering each. This keeps files small and makes adding a command a matter of dropping in one file.
Sharding for large bots
A single process can serve thousands of servers, but once Discord requires sharding (around 2,500 guilds) you'll use discord.js's ShardingManager:
const { ShardingManager } = require("discord.js");
const manager = new ShardingManager("./index.js", { token: process.env.DISCORD_TOKEN });
manager.spawn();
Run the manager under PM2 instead of the bot directly. Most bots never need this — don't add it prematurely.
Troubleshooting
- "Used disallowed intents": you requested a privileged intent (Message Content, Presence, Members) without enabling it in the Developer Portal.
- Commands duplicated: you registered both globally and per-guild — pick one during development.
- Bot offline after deploy: check
pm2 logs; a syntax error or bad token is the usual cause. Node also runs dashboards and APIs happily on the same box — see how to deploy a Node.js app on a VPS.
FAQ
What Node.js version should I use for discord.js?
Use the current LTS (Node 18+ for recent discord.js v14). Older Node versions may fail to start the library.
Why don't my slash commands appear?
You must register them via the REST API (deploy-commands.js). Global commands can take up to an hour to propagate; guild-scoped commands appear instantly.
How do I keep the bot online after I disconnect?
Run it under PM2 (or systemd). Both detach it from your SSH session and restart it on crash and reboot.
Do I need the Message Content intent?
Only if your bot reads message text. Slash-command bots usually don't. Request privileged intents in the Developer Portal only when required.
Ship your discord.js bot on Node.js hosting from Nxeon — NVMe VPS with Node pre-installable via one-click images, full root access, and free migration help.