Bulk-delete messages with /purge

A /purge command that clears a set number of recent messages — optionally only from one member — with the 14-day limit handled and the reply kept private.

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), and ephemeral: true makes 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 a from user is given, .filter() keeps only theirs.
  • channel.bulkDelete(messages, true) is the delete. That true is 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 true flag 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.pinned to 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 true second argument to bulkDelete. 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 from filter 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.

Next steps

Was this guide helpful?