Een van de eerste verwarrende beslissingen bij het bouwen van een Discord-bot is deze: registreer je een slash-commando als een Discord global command of als een commando dat aan een specifieke server (guild) is gekoppeld? Beide komen uit dezelfde code en worden op dezelfde manier geactiveerd, maar hun registratiemethoden, updatetijden en gebruiksscenario's verschillen flink. In dit artikel laat ik beide aanpakken zien met echte discord.js-code en maak ik duidelijk welke je wanneer kiest.
Wat is een global command en wat een guild command?
Een global command is zichtbaar in elke server waar je bot is uitgenodigd, en zelfs in DM's (als je dat toestaat). Je registreert één keer en de bot biedt overal hetzelfde commando aan. Een guild command is alleen zichtbaar in de specifieke server waar je het hebt geregistreerd; daarbuiten gedraagt het zich alsof het commando niet bestaat.
Aan de Discord API-kant komt het onderscheid van twee aparte endpoints:
- Global:
PUT /applications/{application.id}/commands - Guild:
PUT /applications/{application.id}/guilds/{guild.id}/commands
discord.js verpakt deze endpoints met de helpers Routes.applicationCommands() en Routes.applicationGuildCommands().
Het belangrijkste verschil: updatetijd
In de praktijk is het belangrijkste dat de twee methoden scheidt wanneer het commando in de Discord-client verschijnt nadat je het hebt geregistreerd:
- Guild commands worden vrijwel direct bijgewerkt. Ze verschijnen seconden na registratie in het slash-menu. Daardoor zijn ze ideaal voor ontwikkeling en testen.
- Global commands propageren. Discord cachet ze; een wijziging bereikt meestal snel alle clients, maar in het slechtste geval kan het tot een uur duren. Een nieuw commando toevoegen of de beschrijving wijzigen verschijnt mogelijk niet meteen.
Dit ene verschil bepaalt de meeste architectuurkeuzes: terwijl je actief ontwikkelt, wil je niet op global vertrouwen en dan urenlang wachten met de vraag "waarom verschijnt het niet?"
Commando's registreren met discord.js (REST)
Commando's worden meestal geregistreerd met een apart deploy-commands.js-script dat je alleen draait wanneer commando's wijzigen, niet bij elke start van de bot. Hier is een voorbeeld dat naar een guild registreert (discord.js v14):
const { REST, Routes, SlashCommandBuilder } = require('discord.js');
const commands = [
new SlashCommandBuilder()
.setName('ping')
.setDescription('Toont de latency van de bot'),
].map(c => c.toJSON());
const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);
(async () => {
await rest.put(
Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
{ body: commands },
);
console.log('Guild-commando's geregistreerd.');
})();
Om hetzelfde script global te maken, is de enige wijziging het wisselen van de route en het weglaten van de GUILD_ID:
await rest.put(
Routes.applicationCommands(process.env.CLIENT_ID),
{ body: commands },
);
Let op: de put-methode overschrijft. De array die je verstuurt wordt de volledige nieuwe set commando's voor dat bereik (global of die guild). Als je een commando uit de array laat, verwijdert de volgende put het. Dit gedrag is opzettelijk en geeft je idempotente registratie.
Welke gebruik je, en wanneer?
Als algemene regel raad ik deze aanpak aan:
- Gebruik guild commands tijdens ontwikkeling. Registreer ze in je eigen testserver; elke wijziging verschijnt direct en je wacht nooit uren op propagatie.
- Gebruik global commands voor productie. Als de bot in veel servers draait, heeft het geen zin om commando's één voor één aan elke guild te registreren; global bereikt overal in één aanroep.
- Houd guild commands voor serverspecifieke functies. Beheercommando's die bij één community horen, speciale evenementcommando's en dergelijke horen niet global te zijn.
Veel serieuze projecten gebruiken beide: gebruikersgerichte commando's als global, en commando's die alleen in de support-/beheerserver draaien als guild-scoped.
Veelgemaakte fouten
- Dubbele commando's. Als je hetzelfde commando zowel global als als guild command in je testserver registreert, zie je daar twee kopieën. Maak de guild-registratie leeg zodra het testen klaar is (een
putmet een lege array). - De "commando verschijnt niet"-paniek. Een global-wijziging wordt niet direct weerspiegeld; verklaar het niet "kapot" zonder echt tot een uur te wachten. Registreer voor snel testen tijdelijk naar een guild.
- Registratie verwarren met luisteren. Een commando registreren (REST
put) en de binnenkomende interactie afhandelen (deinteractionCreate-event) zijn twee aparte taken. Luister zonder te registreren en het commando verschijnt nooit; registreer zonder te luisteren en je krijgt "Deze interactie is mislukt" bij het klikken. - Verkeerde
CLIENT_ID. Dit is het application-ID, niet dat van de bot (ze komen bij de meeste bots overeen, maar het application-ID is conceptueel het juiste).
Veelgestelde vragen
Duurt een global command echt een uur?
Meestal is het veel sneller en verschijnt de wijziging binnen minuten. Toch garandeert Discord een bovengrens van een uur; vooral bij nieuw toegevoegde commando's kan caching vertraging veroorzaken. Daarom is het gezonder om guild commands voor tests te gebruiken in plaats van op global te vertrouwen.
Kan ik een commando eerst op een guild testen en daarna global maken?
Ja, dit is de meest voorkomende workflow. Je registreert tijdens de ontwikkeling naar een guild en draait het global-script wanneer het klaar is. Denk er alleen aan de testguild-registratie te wissen zodat je geen dubbele commando's ziet.
Hoe verwijder ik een commando?
Een put met een lege array naar de betreffende route verwijdert alle commando's in dat bereik. Om één commando te verwijderen kun je rest.delete() met het ID gebruiken, of het uit de array halen en opnieuw put.
Wil je de commando-architectuur voor je Discord-bot correct opzetten? Ik plan en bouw de global/guild-scope, permissies en propagatiestrategie rond jouw project. Heb je een botproject, neem dan contact met me op.