This recipe gives your discord.js bot a /purge command: pick a number from 1 to 100 and it clears that many recent messages from the channel, optionally filtered to a single member. It uses Discord's bulk-delete, which is fast but has one important rule this code handles for you.
| At a glance | |
|---|---|
| You need | a working bot from Host a discord.js bot |
| Plan | Free or premium |
| Time | About fifteen minutes |
This builds directly on the discord.js bot guide — you should already have a bot answering /ping. We reuse its structure and add one command.
The code
The complete index.js:
require('dotenv').config();
const {
Client, Events, GatewayIntentBits,
SlashCommandBuilder, PermissionFlagsBits,
} = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
const purge = new SlashCommandBuilder()
.setName('purge')
.setDescription('Bulk-delete recent messages in this channel')
.addIntegerOption(o =>
o.setName('amount')
.setDescription('How many messages (1-100)')
.setRequired(true)
.setMinValue(1)
.setMaxValue(100))
.addUserOption(o =>
o.setName('from')
.setDescription('Only delete messages from this member'))
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages);
client.once(Events.ClientReady, async (c) => {
await c.application.commands.set([purge]);
console.log(`Listening as ${c.user.tag}`);
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName !== 'purge') return;
const amount = interaction.options.getInteger('amount');
const from = interaction.options.getUser('from');
await interaction.deferReply({ ephemeral: true });
let messages = await interaction.channel.messages.fetch({ limit: amount });
if (from) messages = messages.filter(m => m.author.id === from.id);
const deleted = await interaction.channel.bulkDelete(messages, true);
await interaction.editReply(
`🧹 Deleted ${deleted.size} message(s).` +
(deleted.size < amount ? ' (Messages older than 14 days can\'t be bulk-deleted.)' : '')
);
});
client.login(process.env.DISCORD_TOKEN);
Paste it into index.js and restart.
The parts that matter
.setMinValue(1).setMaxValue(100)on the integer option keeps the amount in Discord's legal range. Bulk-delete refuses fewer than 2 or more than 100 messages at once, and Discord enforces these bounds before your handler runs.interaction.deferReply({ ephemeral: true })does two jobs. It buys you more than the usual three seconds (fetching and deleting takes a moment), andephemeral: truemakes the confirmation visible only to the moderator who ran the command — so your "deleted 50 messages" reply doesn't become the newest thing in a freshly-cleared channel.channel.messages.fetch({ limit: amount })pulls the most recent messages so you can count and optionally filter them. When afromuser is given,.filter()keeps only theirs.channel.bulkDelete(messages, true)is the delete. Thattrueis the key: it tells discord.js to silently skip messages older than 14 days instead of throwing an error. Without it, one old message in the batch would fail the entire call.
🎯 Good to know: Discord's bulk-delete API physically cannot remove messages older than 14 days — that's a platform rule, not a bot limitation. The
trueflag and the "older than 14 days" note in the reply are how this recipe stays honest about it. To clear ancient messages you'd delete them one at a time, which is slow and rate-limited.
Permissions and intents
No privileged intents — GatewayIntentBits.Guilds is all you need, nothing to toggle in the Developer Portal.
The bot's role needs two permissions in the server:
| Permission | Why |
|---|---|
| Manage Messages | to delete other people's messages |
| Read Message History | to fetch the messages before deleting them |
setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) also hides the command from members who can't Manage Messages, so only your moderators see /purge.
Making it yours
- Confirm before big deletes. For a "clear the whole channel" button, post a button that asks "Are you sure?" first.
- Filter by content. After the fetch,
.filter(m => m.content.includes('spam'))deletes only matching messages — handy for cleaning up one bad link. - Skip pinned messages. Add
&& !m.pinnedto your filter so important pins survive a purge. - Log what you cleared. Before deleting, send the message count (and channel) to a mod-log channel so there's a paper trail.
Troubleshooting
- "You can only bulk delete messages that are under 14 days old" — you're missing the
truesecond argument tobulkDelete. Add it; the code above already does. - Nothing gets deleted and the reply says 0 — every candidate message was older than 14 days, or the
fromfilter matched nobody. Check the channel's age and the user you picked. - "Missing Permissions" — the bot's role lacks Manage Messages or Read Message History in that channel. Channel-level permission overrides can block it even when the server role allows it.
- "This interaction failed" — a fetch or delete took too long before you replied. The
deferReply()in the code prevents this; make sure it's still there and runs before the fetch.