Skip to content

Node.js Guide

This guide walks you through deploying a Discord bot in Node.js on KataBump. We'll use the discord.js library, which is the most popular and complete.

Prerequisites

  • Node.js installed on your machine (for development)
  • A Discord bot created on the Developer Portal
  • Your bot's token

Create Your Project

/my-discord-bot/
├── package.json
├── index.js
├── .env (local only)
└── commands/
    └── ping.js

1. Initialize the Project

bash
mkdir my-discord-bot
cd my-discord-bot
npm init -y

2. Install discord.js

bash
npm install discord.js

3. Create package.json

Make sure your package.json looks like this:

json
{
  "name": "my-discord-bot",
  "version": "1.0.0",
  "description": "My Discord bot hosted on KataBump",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "node index.js"
  },
  "dependencies": {
    "discord.js": "^14.14.1"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

"start" Script

The "start" script is required. This is the command KataBump uses to start your bot.

4. Create the Bot

Create an index.js file:

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

// Create the Discord client
const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent,
        GatewayIntentBits.GuildMembers
    ]
});

// "ready" event - when the bot is connected
client.once(Events.ClientReady, (readyClient) => {
    console.log(`Connected as ${readyClient.user.tag}`);
    console.log(`ID: ${readyClient.user.id}`);
});

// Respond to messages
client.on(Events.MessageCreate, (message) => {
    // Ignore messages from the bot itself
    if (message.author.bot) return;
    
    // !ping command
    if (message.content === '!ping') {
        message.reply('Pong!');
    }
    
    // !hello command
    if (message.content === '!hello') {
        message.reply(`Hello ${message.author.username}!`);
    }
});

// Connect with the environment token
const TOKEN = process.env.DISCORD_TOKEN;

if (!TOKEN) {
    console.error('Error: DISCORD_TOKEN variable is not defined');
    process.exit(1);
}

client.login(TOKEN).catch((error) => {
    console.error('Connection error:', error);
    process.exit(1);
});

// Error handling
process.on('unhandledRejection', (error) => {
    console.error('Unhandled error:', error);
});

5. Set Up Environment Variables

Create a .env file at the root of your project:

DISCORD_TOKEN=your_token_here

Install dotenv as a dependency:

bash
npm install dotenv

Add the following at the very top of index.js:

javascript
require('dotenv').config();

.env on KataBump

The .env file is used both locally and on KataBump. Upload it to your server along with your other files. See Set Environment Variables for more details.

6. Test Locally (optional)

bash
npm start

::: success Works Locally? If your bot works locally, it will work on KataBump! :::

Deploy to KataBump

1. Create a Node.js Server

  1. Log in to dashboard.katabump.com
  2. Click "Create a server"
  3. Choose Node.js
  4. Name your server
  5. Click "Create"
  6. On control.katabump.com, go to the "Startup" tab to select your Node.js version (recommended: 18 or 20 LTS)

2. Upload Files

Via Web

  1. Create a ZIP file containing your project files
  2. Go to the "Files" tab on control.katabump.com
  3. Drag and drop your ZIP file
  4. Unzip the file on the panel
  5. Make sure package.json and index.js are at the root

Via SFTP

  1. Retrieve your SFTP credentials in the "Settings" section
  2. Connect with FileZilla
  3. Upload files to /home/container

3. Configure Startup

  1. Go to the "Startup" tab on control.katabump.com
  2. Set the "JS FILE" to your entry point (e.g. index.js)
  3. Save

Environment Variables

Your .env file (containing your DISCORD_TOKEN) should already be included in your uploaded files. If not, upload it via the file manager or SFTP.

4. Start the Server

  1. Go to the "Console" tab
  2. Click "Start"
  3. Wait for dependency installation (automatic npm install)
  4. You should see:
    Connected as MyBot#1234
    ID: 123456789

::: success Bot Online! Your bot is now connected 24/7! :::

Slash Commands

Slash commands are the new standard recommended by Discord.

Example with Slash Commands

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

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

// Commands to register
const commands = [
    new SlashCommandBuilder()
        .setName('ping')
        .setDescription('Responds with Pong!'),
    new SlashCommandBuilder()
        .setName('info')
        .setDescription('Displays information')
];

client.once(Events.ClientReady, async (readyClient) => {
    console.log(`Connected as ${readyClient.user.tag}`);
    
    // Register commands (do this only once)
    try {
        await readyClient.application.commands.set(commands);
        console.log('Slash commands registered');
    } catch (error) {
        console.error('Registration error:', error);
    }
});

// Handle interactions
client.on(Events.InteractionCreate, async (interaction) => {
    if (!interaction.isChatInputCommand()) return;
    
    if (interaction.commandName === 'ping') {
        await interaction.reply('Pong!');
    }
    
    if (interaction.commandName === 'info') {
        await interaction.reply({
            content: `**Information**\n` +
                     `Server: ${interaction.guild.name}\n` +
                     `Members: ${interaction.guild.memberCount}`,
            ephemeral: true  // Message visible only to the user
        });
    }
});

client.login(process.env.DISCORD_TOKEN);

Command Registration

Slash commands need to be registered once, then Discord caches them. Modify the code to register, start, then comment out the registration part.

Best Practices

Error Handling

javascript
// Always handle errors
client.on(Events.Error, (error) => {
    console.error('Discord error:', error);
});

// Unhandled errors
process.on('unhandledRejection', (error) => {
    console.error('Unhandled rejection:', error);
});

process.on('uncaughtException', (error) => {
    console.error('Uncaught exception:', error);
    process.exit(1);
});

Using PM2 (optional)

For advanced process management, you can use PM2:

json
// package.json
{
  "scripts": {
    "start": "pm2-runtime start ecosystem.config.js"
  },
  "dependencies": {
    "pm2": "^5.3.0"
  }
}
javascript
// ecosystem.config.js
module.exports = {
    apps: [{
        name: 'discord-bot',
        script: './index.js',
        instances: 1,
        autorestart: true,
        watch: false,
        max_memory_restart: '250M'
    }]
};

Memory Optimization

json
// package.json
{
  "scripts": {
    "start": "node --max-old-space-size=256 index.js"
  }
}

Free Plan Memory

The free plan provides 308 MB RAM. Set --max-old-space-size accordingly to avoid OOM errors.

Next Steps

Official KataBump Documentation