Skip to main content
Once your bot is ready, deploy it to production for 24/7 uptime. This guide covers building, optimizing, and hosting your CommandKit bot.

Building for Production

CommandKit includes a build system that optimizes your bot for production.
1

Build your bot

Run the build command to compile your TypeScript and optimize your code:
npm run build
This creates a dist/ directory with your compiled code.
2

Test the build

Start your bot in production mode:
npm run start
Verify all commands and features work correctly.
3

Prepare environment variables

Ensure all required environment variables are configured:
.env
DISCORD_TOKEN=your_production_bot_token
DISCORD_CLIENT_ID=your_bot_client_id
NODE_ENV=production

# Optional: Database and other services
DATABASE_URL=your_production_database_url
REDIS_URL=your_redis_url
Never commit .env files or expose your bot token. Use environment variables or secret management services.

Package.json Scripts

Ensure your package.json has these scripts:
package.json
{
  "scripts": {
    "dev": "commandkit dev",
    "build": "commandkit build",
    "start": "commandkit start"
  }
}
  • dev - Development mode with hot reload
  • build - Compile TypeScript and optimize for production
  • start - Run the production build

Hosting Options

Railway

Railway provides simple deployment with GitHub integration.
1

Create Railway account

Sign up at railway.app and connect your GitHub account.
2

Create new project

Click New ProjectDeploy from GitHub repo → Select your bot repository.
3

Add environment variables

In your project settings, add:
  • DISCORD_TOKEN
  • DISCORD_CLIENT_ID
  • Any other required variables
4

Configure start command

Railway auto-detects Node.js projects. Ensure your package.json has the start script:
{
  "scripts": {
    "start": "commandkit start"
  }
}
5

Deploy

Railway automatically builds and deploys on every push to your main branch.

Heroku

Heroku is a popular platform for hosting bots.
1

Install Heroku CLI

npm install -g heroku
2

Login and create app

heroku login
heroku create your-bot-name
3

Add buildpack

heroku buildpacks:set heroku/nodejs
4

Set environment variables

heroku config:set DISCORD_TOKEN=your_token
heroku config:set DISCORD_CLIENT_ID=your_client_id
5

Create Procfile

Procfile
worker: npm run start
6

Deploy

git add .
git commit -m "Deploy to Heroku"
git push heroku main
7

Scale worker

heroku ps:scale worker=1

DigitalOcean

Deploy on a VPS for full control.
1

Create droplet

Create an Ubuntu droplet on DigitalOcean.
2

SSH into server

ssh root@your_server_ip
3

Install Node.js

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
4

Clone repository

git clone https://github.com/yourusername/your-bot.git
cd your-bot
npm install
5

Create .env file

nano .env
Add your environment variables:
DISCORD_TOKEN=your_token
DISCORD_CLIENT_ID=your_client_id
Save with Ctrl+X, then Y, then Enter.
6

Build and start

npm run build
npm run start
7

Use PM2 for process management

Install PM2 to keep your bot running:
npm install -g pm2
pm2 start npm --name "discord-bot" -- run start
pm2 startup
pm2 save
PM2 automatically restarts your bot if it crashes and starts on server reboot.

Docker

Containerize your bot for consistent deployment.
1

Create Dockerfile

Dockerfile
FROM node:24-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

CMD ["npm", "run", "start"]
2

Create .dockerignore

.dockerignore
node_modules
dist
.env
.git
.gitignore
3

Build image

docker build -t discord-bot .
4

Run container

docker run -d \
  --name discord-bot \
  --env-file .env \
  --restart unless-stopped \
  discord-bot

Process Management

Using PM2

PM2 is a production process manager for Node.js applications.
# Install PM2 globally
npm install -g pm2

# Start your bot
pm2 start npm --name "discord-bot" -- run start

# View logs
pm2 logs discord-bot

# Restart bot
pm2 restart discord-bot

# Stop bot
pm2 stop discord-bot

# Auto-start on system boot
pm2 startup
pm2 save

PM2 Ecosystem File

Create advanced PM2 configurations:
ecosystem.config.js
module.exports = {
  apps: [{
    name: 'discord-bot',
    script: 'npm',
    args: 'run start',
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env: {
      NODE_ENV: 'production',
    },
    error_file: './logs/err.log',
    out_file: './logs/out.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
  }],
};
Start with:
pm2 start ecosystem.config.js

Environment Variables

Required Variables

.env
# Required
DISCORD_TOKEN=your_bot_token
DISCORD_CLIENT_ID=your_client_id

# Optional but recommended
NODE_ENV=production

Managing Secrets

Add variables in project settings → Variables

Logging and Monitoring

CommandKit Logger

Use the built-in logger for consistent logging:
src/app.ts
import { Logger } from 'commandkit/logger';

Logger.info('Bot starting...');
Logger.warn('This is a warning');
Logger.error('An error occurred', error);

Log Files with PM2

PM2 automatically manages log files:
# View live logs
pm2 logs discord-bot

# View only errors
pm2 logs discord-bot --err

# Clear logs
pm2 flush

External Monitoring

Consider using monitoring services:
  • Sentry - Error tracking and performance monitoring
  • Datadog - Comprehensive monitoring and analytics
  • UptimeRobot - Uptime monitoring

Database Considerations

If your bot uses a database:
1

Use production database

Don’t use your development database in production. Set up a separate production database:
DATABASE_URL=postgresql://user:password@host:5432/production_db
2

Run migrations

If using Prisma or similar:
npx prisma migrate deploy
3

Enable connection pooling

Use connection pooling for better performance:
src/database.ts
import { PrismaClient } from '@prisma/client';

export const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
    },
  },
});
4

Backup regularly

Set up automated backups for your production database.

Performance Optimization

Enable Production Mode

.env
NODE_ENV=production
This enables optimizations in Discord.js and CommandKit.

Reduce Memory Usage

src/app.ts
import { Client, IntentsBitField } from 'discord.js';

const client = new Client({
  intents: [
    // Only enable intents you need
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
  ],
  // Reduce cache size
  makeCache: manager => {
    if (manager.name === 'MessageManager') {
      return manager.cache.sweep(m => m.author.id === client.user?.id);
    }
    return manager.cache;
  },
});

Use Caching

Implement caching for frequently accessed data:
import { cache } from '@commandkit/cache';

// Cache guild settings
const settings = await cache('guild-settings', guildId, async () => {
  return await database.fetchGuildSettings(guildId);
}, { ttl: 300 }); // 5 minutes

Continuous Deployment

GitHub Actions

Automate deployments with GitHub Actions:
.github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '24'
          
      - name: Install dependencies
        run: npm ci
        
      - name: Build
        run: npm run build
        
      - name: Deploy to Railway
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
        run: |
          npm install -g @railway/cli
          railway up

Health Checks

Implement health checks to ensure your bot is running:
src/app/events/clientReady/health-check.ts
import type { EventHandler } from 'commandkit';
import { Logger } from 'commandkit/logger';

export const once = true;

const handler: EventHandler<'clientReady'> = async (client) => {
  // Periodic health check every 5 minutes
  setInterval(() => {
    Logger.info('Health check: Bot is running');
    Logger.info(`Ping: ${client.ws.ping}ms`);
    Logger.info(`Guilds: ${client.guilds.cache.size}`);
    Logger.info(`Memory: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB`);
  }, 5 * 60 * 1000);
};

export default handler;

Troubleshooting

Bot Not Starting

  1. Check logs for errors
  2. Verify environment variables are set
  3. Ensure bot token is valid
  4. Check Node.js version (requires Node.js 24+)

High Memory Usage

  1. Reduce Discord.js cache size
  2. Implement proper garbage collection
  3. Clear old data from memory
  4. Use database for long-term storage

Commands Not Updating

  1. Wait a few minutes for Discord to propagate changes
  2. Check if bot has proper permissions
  3. Verify DISCORD_CLIENT_ID is correct
  4. Try removing and re-adding bot to server

Best Practices

  • Use TypeScript: Better error detection and type safety
  • Enable logging: Monitor your bot’s activity and errors
  • Implement rate limiting: Prevent abuse and API overuse
  • Handle errors gracefully: Never let errors crash your bot
  • Use environment variables: Never hardcode sensitive data
  • Set up automated backups: Protect your data
  • Monitor performance: Track memory usage and response times
  • Keep dependencies updated: Regular updates improve security and performance

Build docs developers (and LLMs) love