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:
- Scans selected slash command directories
- Recursively loads command files
- Extracts
SlashCommandBuilderdefinitions - Converts them into JSON
- Registers them using Discord’s REST API
- 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