ns Docsns Docs
Utilities

Deploy Slash Commands

Utility for discovering, serializing, and registering slash commands with Discord using the REST API.

Introduction

The Deploy Slash Commands utility is responsible for registering your bot’s slash commands with Discord.

Unlike message commands, slash commands must be explicitly deployed to Discord before users can access them.

This script is usually run manually or during deployment, not during normal bot startup.


Why Slash Commands Need Deployment

Slash commands are stored on Discord’s servers, not loaded dynamically at runtime.

This means:

  • New commands won’t appear automatically
  • Changes require re-deployment
  • Deleted commands must be explicitly removed

This utility ensures Discord stays in sync with your codebase.


What This Utility Does

At a high level, this utility:

  1. Scans selected slash command directories
  2. Recursively loads command files
  3. Extracts SlashCommandBuilder definitions
  4. Converts them into JSON
  5. Registers them using Discord’s REST API
  6. Logs progress and errors clearly

Full Deployment Utility Code

import { REST, Routes, SlashCommandBuilder } from 'discord.js'
import { readdirSync, statSync } from 'fs'
import { join, extname } from 'path'
import { logger } from './logger'
import config from '../configs/botConfig'

interface SlashCommandJSON {
  name: string
  description: string
  options?: Array<any>
}

// List of directories to include
const includeDirectories = ['commands/slashCommands/general', 'commands/slashCommands/info']

const loadSlashCommands = (dirs: string[]): Promise<SlashCommandJSON[]> => {
  return new Promise((resolve, reject) => {
    const commands: SlashCommandJSON[] = []

    const loadCommandsFromDir = async (dir: string) => {
      const files = readdirSync(dir)

      for (const file of files) {
        const filePath = join(dir, file)
        const fileStat = statSync(filePath)

        if (fileStat.isDirectory()) {
          await loadCommandsFromDir(filePath)
        } else if (extname(file) === '.ts' || extname(file) === '.js') {
          const commandModule = await import(filePath)
          const command = commandModule.default

          if (command && command.data instanceof SlashCommandBuilder) {
            commands.push(command.data.toJSON())
          }
        }
      }
    }

    Promise.all(dirs.map(dir => loadCommandsFromDir(dir)))
      .then(() => resolve(commands))
      .catch(reject)
  })
}

// Convert includeDirectories to absolute paths
const absoluteIncludeDirectories = includeDirectories.map(dir => join(__dirname, '../', dir))

// Load slash commands
loadSlashCommands(absoluteIncludeDirectories)
  .then(commands => {
    const rest = new REST({ version: '10' }).setToken(config.BOT_TOKEN!)

    logger.info('DeployCommands', 'Started refreshing application (/) commands.')

    return rest.put(Routes.applicationCommands(config.BOT_ID!), {
      body: commands,
    })
  })
  .then(() => {
    logger.success('DeployCommands', 'Successfully reloaded application (/) commands.')
  })
  .catch(error => {
    if (error instanceof Error) {
      logger.error('DeployCommands', `Error registering commands: ${error.message}`)
    } else {
      logger.error('DeployCommands', 'Unknown error occurred while registering commands.')
    }
  })

Explanation

Directory Filtering

Only directories listed in includeDirectories are scanned.

This gives you full control over which commands are deployed and prevents accidental registrations.


Recursive Command Discovery

The utility walks through folders recursively, allowing:

  • Nested command categories
  • Clean project structure
  • Automatic discovery without manual imports

SlashCommandBuilder Validation

Only commands exporting a valid SlashCommandBuilder are registered.

This prevents:

  • Invalid files from being deployed
  • Runtime API errors
  • Broken command definitions

REST-Based Registration

Commands are registered using:

  • Discord REST API (v10)
  • Bot token authentication
  • Application-level command route

This avoids the need to spin up a Discord client.


Logging & Error Handling

The utility uses your centralized logger to:

  • Track deployment progress
  • Clearly report failures
  • Keep logs consistent across tools

This makes command deployment safe, repeatable, and production-ready.


When Should You Run This?

Run this utility when:

  • You add a new slash command
  • You modify command options
  • You rename or remove commands
  • You deploy a new version of your bot

Add "deploy": "node dist/utils/deployCommands.js" script in package.json.

Last updated on

On this page