Discord Bot
Build Discord bots using discord.js with slash commands, embeds, permissions,
You are a Discord bot developer who builds interactive bots using discord.js. You create slash commands, handle gateway events, send rich embeds, manage permissions, and build message components like buttons and select menus while following Discord's API rate limits and intent requirements. ## Key Points - **Enabling all gateway intents** - wastes resources and requires privileged intent approval for no reason. - **Registering global commands during development** - they take up to an hour to update; use guild commands in dev. - **Not deferring replies before async work** - causes "This interaction failed" if the response takes over 3 seconds. - **Storing bot tokens in client-side code or public repos** - tokens grant full bot access; rotate immediately if leaked. - Building moderation bots that respond to slash commands and manage server members. - Creating utility bots that provide server stats, reminders, or role assignment. - Building interactive experiences with buttons, select menus, and modals. - Integrating external services (CI/CD, monitoring, alerts) into Discord channels. - Creating music or entertainment bots that respond to user commands in voice or text channels. ## Quick Example ```bash npm install discord.js @discordjs/rest npm install -D @types/node ``` ```bash DISCORD_BOT_TOKEN=your-bot-token DISCORD_CLIENT_ID=your-application-client-id DISCORD_GUILD_ID=your-dev-server-id # for dev command registration ```
skilldb get oauth-social-services-skills/Discord BotFull skill: 182 linesDiscord Bot API Integration
You are a Discord bot developer who builds interactive bots using discord.js. You create slash commands, handle gateway events, send rich embeds, manage permissions, and build message components like buttons and select menus while following Discord's API rate limits and intent requirements.
Core Philosophy
Declare Only Needed Gateway Intents
Discord requires bots to declare which events they want to receive via Gateway Intents. Privileged intents (message content, presence, guild members) require manual approval in the Developer Portal for bots in 100+ servers. Only enable intents your bot actually uses. A slash-command-only bot needs Guilds and nothing else. Enabling unnecessary intents wastes memory and bandwidth.
Slash Commands over Prefix Commands
Message-content-based prefix commands require the privileged MessageContent intent and are unreliable in DMs. Slash commands are discoverable, type-safe, support autocomplete, and work without any privileged intents. Always register commands via the REST API and handle them through the interactionCreate event. Use guild-scoped commands during development for instant updates; deploy globally for production.
Defer Long-Running Interactions
Discord requires an interaction response within 3 seconds. If your command does async work (API calls, database queries), call interaction.deferReply() immediately, then follow up with interaction.editReply() when ready. Failing to respond in time shows "This interaction failed" to the user. For buttons and modals, use deferUpdate() to acknowledge without sending a new message.
Setup
Install
npm install discord.js @discordjs/rest
npm install -D @types/node
Environment Variables
DISCORD_BOT_TOKEN=your-bot-token
DISCORD_CLIENT_ID=your-application-client-id
DISCORD_GUILD_ID=your-dev-server-id # for dev command registration
Key Patterns
1. Bot Client Setup - Do specify minimal intents
import { Client, GatewayIntentBits, Events } from "discord.js";
const client = new Client({
intents: [GatewayIntentBits.Guilds], // add more only if needed
});
client.once(Events.ClientReady, (c) => {
console.log(`Logged in as ${c.user.tag}`);
});
client.login(process.env.DISCORD_BOT_TOKEN);
2. Slash Command Registration - Do use guild commands in dev
import { REST, Routes } from "discord.js";
const commands = [
{
name: "ping",
description: "Check bot latency",
},
{
name: "remind",
description: "Set a reminder",
options: [
{ name: "message", type: 3, description: "Reminder text", required: true },
{ name: "minutes", type: 4, description: "Minutes from now", required: true },
],
},
];
const rest = new REST().setToken(process.env.DISCORD_BOT_TOKEN!);
// Guild commands update instantly (use in dev)
await rest.put(
Routes.applicationGuildCommands(process.env.DISCORD_CLIENT_ID!, process.env.DISCORD_GUILD_ID!),
{ body: commands }
);
// Global commands take up to 1 hour to propagate (use in prod)
// await rest.put(Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!), { body: commands });
3. Interaction Handling - Do not forget to defer long operations
import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "ping") {
const latency = client.ws.ping;
await interaction.reply(`Pong! Latency: ${latency}ms`);
}
if (interaction.commandName === "remind") {
await interaction.deferReply({ ephemeral: true });
const message = interaction.options.getString("message", true);
const minutes = interaction.options.getInteger("minutes", true);
// Schedule reminder...
await interaction.editReply(`Reminder set for ${minutes} minutes: "${message}"`);
}
});
Common Patterns
Rich Embeds
const embed = new EmbedBuilder()
.setTitle("Server Stats")
.setColor(0x5865f2)
.addFields(
{ name: "Members", value: `${interaction.guild?.memberCount}`, inline: true },
{ name: "Channels", value: `${interaction.guild?.channels.cache.size}`, inline: true }
)
.setTimestamp();
await interaction.reply({ embeds: [embed] });
Button Components
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId("confirm").setLabel("Confirm").setStyle(ButtonStyle.Success),
new ButtonBuilder().setCustomId("cancel").setLabel("Cancel").setStyle(ButtonStyle.Danger)
);
await interaction.reply({ content: "Are you sure?", components: [row] });
// Handle button press
client.on(Events.InteractionCreate, async (i) => {
if (!i.isButton()) return;
if (i.customId === "confirm") {
await i.update({ content: "Confirmed!", components: [] });
}
});
Permission Checks
import { PermissionFlagsBits } from "discord.js";
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "ban") {
if (!interaction.memberPermissions?.has(PermissionFlagsBits.BanMembers)) {
return interaction.reply({ content: "You lack Ban Members permission.", ephemeral: true });
}
// proceed with ban logic
}
});
Anti-Patterns
- Enabling all gateway intents - wastes resources and requires privileged intent approval for no reason.
- Registering global commands during development - they take up to an hour to update; use guild commands in dev.
- Not deferring replies before async work - causes "This interaction failed" if the response takes over 3 seconds.
- Storing bot tokens in client-side code or public repos - tokens grant full bot access; rotate immediately if leaked.
When to Use
- Building moderation bots that respond to slash commands and manage server members.
- Creating utility bots that provide server stats, reminders, or role assignment.
- Building interactive experiences with buttons, select menus, and modals.
- Integrating external services (CI/CD, monitoring, alerts) into Discord channels.
- Creating music or entertainment bots that respond to user commands in voice or text channels.
Install this skill directly: skilldb add oauth-social-services-skills
Related Skills
Github OAUTH
Integrate GitHub OAuth Apps and the GitHub API into TypeScript applications.
Google OAUTH
Integrate Google OAuth 2.0 and Google APIs into TypeScript applications.
Linkedin API
Integrate the LinkedIn API into TypeScript applications. Covers OAuth 2.0
Notion API
Integrate the Notion API into TypeScript applications. Covers OAuth
Slack API
Build Slack integrations using the Bolt framework in TypeScript. Covers
Spotify API
Integrate the Spotify Web API into TypeScript applications. Covers OAuth 2.0