Registering commands
Learn how to register slash commands and context menus in Discord using Sunar. This guide includes global, guild-specific, dynamic registration, and usage of the --register flag.
Sunar provides flexible ways to register your Discord bot commands, either globally or per server (guild), with support for runtime configuration and dynamic behavior.
Create a command
Define a new slash command or a context menu using Sunar's builders:
import { Slash, execute } from 'sunar';
const slash = new Slash({
name: 'ping',
description: "Ping the bot to check if it's online.",
});
execute(slash, (interaction) => {
interaction.reply('Pong!');
});
export { slash };Listen for the ready signal
This ensures your bot only attempts to register commands once it's connected to Discord:
import { Signal, Signals, execute } from 'sunar';
const signal = new Signal(Signals.ClientReady, { once: true });
execute(signal, (client) => {
console.log(`${client.user.tag} is online!`);
});
export { signal };Register commands dynamically
Use the registerCommands function from sunar/registry to register all stored commands at runtime. This is the recommended default if you want automatic detection with minimal setup:
import { Signal, Signals, execute } from 'sunar';
import { registerCommands } from 'sunar/registry';
const signal = new Signal(Signals.ClientReady, { once: true });
execute(signal, async (client) => {
await registerCommands(client.application);
console.log(`${client.user.tag} logged!`);
});
export { signal };By default, this registers commands globally. You can override that behavior with per-command configuration or by using dedicated functions.
Avoid registering commands repeatedly in a short time—Discord rate limits apply. Use the --register flag to control registration timing. See Using the --register flag section.
Registering for Specific Guilds (Recommended for Development)
To avoid waiting for Discord's global command propagation (which can take up to an hour), use registerGuildCommands during development:
import { Signal, Signals, execute } from 'sunar';
import { registerGuildCommands } from 'sunar/registry';
const signal = new Signal(Signals.ClientReady, { once: true });
execute(signal, async (client) => {
await registerGuildCommands(client.application, ['YOUR_GUILD_ID']);
console.log(`${client.user.tag} logged!`);
});
export { signal };Use this method only during development. It ensures commands are registered instantly and avoids delays, but limits them to specific servers.
Replace 'YOUR_GUILD_ID' with your actual Discord server ID(s).
Explicit Global Registration
If you want to explicitly force all commands to be registered globally, regardless of any per-command configuration (like guildIds), you can use registerGlobalCommands:
import { Signal, Signals, execute } from 'sunar';
import { registerGlobalCommands } from 'sunar/registry';
const signal = new Signal(Signals.ClientReady, { once: true });
execute(signal, async (client) => {
await registerGlobalCommands(client.application);
console.log(`${client.user.tag} logged!`);
});
export { signal };This method bypasses any guildIds specified in your command configurations and forces all commands to be global.
Use it only if you have a very specific use case that requires this behavior.
Prefer using registerCommands() for production — it respects per-command configuration and behaves globally by default.
Command-Specific Guild Registration
You can also control registration behavior on a per-command basis using the config mutator:
import { Slash, execute, config } from 'sunar';
const slash = new Slash({
name: 'ping',
description: "Ping the bot to check if it's online.",
});
config(slash, {
guildIds: ['YOUR_GUILD_ID'],
});
execute(slash, (interaction) => {
interaction.reply('Pong!');
});
export { slash };This allows you to mix global and guild-specific commands without changing your registration strategy.
Using the --register flag
To separate registration from normal bot startup, you can use a CLI flag like --register. This is especially useful to avoid unnecessary re-registration during development or to prevent global command delays.
In your ready signal:
import { Signal, Signals, execute } from 'sunar';
import { registerCommands } from 'sunar/registry';
const signal = new Signal(Signals.ClientReady, { once: true });
execute(signal, async (client) => {
if (process.argv.includes('--register')) {
await registerCommands(client.application);
console.log('Commands registered');
}
console.log(`${client.user.tag} logged!`);
});
export { signal };Run your bot with:
node src/index.js --registerOr with Bun:
bun src/index.ts --registerOr using tsx:
tsx src/index.ts --registerThis pattern prevents command re-registration on every bot restart. Global commands, in particular, are slow to propagate, so registering them on-demand is preferred. You can also add a shortcut script in your package.json:
{
// ...
"scripts": {
"register": "node src/index.js --register"
}
// ...
}Summary
Sunar provides full flexibility over how and when your commands are registered:
- Use
registerGuildCommands()during development for instant updates. - Use
registerCommands()in production — it's dynamic, respectsguildIds, and behaves globally by default. - Use
config(..., { guildIds })to mix both styles per command. - Use
registerGlobalCommands()only if you need to forcibly override all command scopes. - Use the
--registerflag to control when commands are registered.
How is this guide?
Last updated on
Interactions handling
Learn how to effectively manage interactions between your bot and users using Sunar. From responding to slash commands, context menu clicks, button presses, to select menu choices, Sunar offers robust mechanisms to handle diverse interactions within Discord.
Using Components
Learn how to add interactivity to your application using Discord components.