How to automate a Discord server
The automation patterns worth building, event-driven versus scheduled, where Discord AutoMod belongs, and the limits nobody tells you about before you start.
Server automation is a small number of patterns repeated everywhere. Learn the patterns and the limits, and you can build the rest from the shape.
Everything here splits into two families. Event-driven automation runs when something happens: a member joins, a reaction lands, someone gets banned, a voice channel fills up. Scheduled automation runs at a time: every Monday at 9am, every hour, once on the 14th. Almost every real automation is one of those two, and a surprising number of setups break because someone built one when they needed the other.
Event-driven patterns
Welcome and autorole
The default first automation, and the one most servers get slightly wrong by splitting it into two things.
One trigger, two actions: on member join, post a greeting and assign the base role. Doing both in one automation means they cannot drift apart, and a member can never end up greeted but roleless.
@Bond set up a welcome flow that greets new members in #general and gives them the Member role
What that becomes internally is a member_join flow with a condition excluding bots, a message, and a role assignment. The bot-exclusion matters: without it, every bot you invite gets welcomed and handed a member role.
Two details worth fixing at the same time:
- Turn off Discord's own join message. Server Settings, Overview, system channel settings. Otherwise members get greeted twice.
- Decide what happens on leave. Public goodbye messages age badly in a server with churn. A quiet line in a staff channel is usually the better version.
See welcome messages, auto-assign roles on join, and goodbye messages.
The verification gate
A gate is three parts, and it is not finished until all three exist:
- Channel permissions that hide the server from unverified members.
- A role that unhides it.
- A thing that grants the role: a button, a command, or a reaction.
People build parts 1 and 2, test with their own admin account (which bypasses everything), and ship a gate that does not gate. If you build one, verify it with a second account, or ask the bot to check access per role rather than trusting the overwrites it just wrote.
@Bond make people click a button in #verify to get the Verified role, and hide everything else until they do
Then, before you announce it:
@Bond what can an unverified member see right now?
See set up member verification.
Self-assignable roles: three options
| Approach | How it works | Best for |
|---|---|---|
| Reaction roles | Bot watches reactions on a specific message and assigns roles | Servers already using them, or where you want emoji as the interface |
| Button and select panel | A message with real Discord components wired to a command | Most cases. Shows role names, cannot be broken by removing a reaction |
| Discord Onboarding | Native. New members answer questions and get roles and channels | Community servers, for first-join role choice |
Onboarding is the one people forget. It is built into Discord, it runs before anyone talks to a bot, and it handles the "pick your interests" case natively. Server Settings, Onboarding, on desktop, with Community enabled. It needs Manage Server plus Manage Roles.
The catch is that Onboarding only fires at join. It does nothing for a member who joined last year and now wants the Music role. So most servers want both: Onboarding for first-join choices, and a panel in a #roles channel for everything after.
Panels have hard limits worth knowing before you design one: 25 components per message, 5 rows, 5 buttons per row, and a select menu takes a whole row.
See reaction roles.
Logging
Discord's audit log exists, and nobody reads it, because it is a separate screen you have to remember to open. Piping the events you care about into a staff channel is the version people actually use.
@Bond post in #mod-log every time someone is banned or unbanned, with the reason
Useful triggers to hang logging off: member_banned, member_unbanned, member_leave, channel_created, channel_deleted, role_created, role_deleted, role_updated.
Log role changes if you have more than a handful of staff. It is the cheapest early warning for a compromised moderator account. See log moderation actions to a channel.
Voice and thread events
Underused. Voice triggers (voice_join, voice_leave, voice_move) let you announce when a stage goes live, track voice activity per member, or post a "people are in VC" ping without anyone typing. Thread triggers (thread_created) let you auto-post a template in every new support thread.
Event-driven with stored data
The pattern that unlocks the rest: an automation that reads and writes persistent per-server storage.
Counting messages per member is a message_sent trigger that increments a number. Once that number exists, it can drive a level role, a /rank command, and a weekly leaderboard post, all reading the same stored value. Same shape for coins, warnings, streaks, and birthdays.
@Bond track message counts, give the Regular role at level 5, and make a /leaderboard command showing the top 10
See leaderboards and levels, economy system, and track member activity.
Scheduled patterns
Recurring announcements
The obvious one, and the one that pays for itself fastest in a server with a weekly rhythm.
@Bond post the weekly event schedule in #announcements every Monday at 9am IST
Always state a timezone. Schedules default to UTC, and "9am" meaning 2:30pm to your members is the most common complaint about scheduled posts. See scheduled announcements.
One-time scheduled posts
Distinct from recurring, and often what people actually want. Write the message now, pick a time, it fires once and disables itself.
@Bond post the event details in #general at 6pm on Saturday
See schedule a message for later.
Cleanup on a schedule
A #bot-spam or #memes channel that grows forever is a search problem later. Clearing it nightly is one scheduled automation.
@Bond clear out #bot-spam every night at 3am
Note the platform limit: Discord refuses bulk deletion of messages older than 14 days. A nightly job is fine. A one-off "delete everything from 2023" is not a bulk operation, it is a slow one. See auto-delete messages.
The closing job
The pattern most people miss. A timed thing is not set up until the thing that ends it exists.
A giveaway is not one automation, it is two: the announcement with the entry reaction, and a one-time scheduled job that reads the entrants, picks a winner, and edits the original message. A temporary channel unlock is the unlock plus the relock. A poll that closes is the poll plus the close.
If you only build the first half, the server ends up with a giveaway that never resolves and a locked channel nobody remembers unlocking.
@Bond run a giveaway in #events, react to enter, pick a winner in 24 hours
See run a giveaway.
Auto-moderation: layer it
Auto-moderation is three layers, and they do different jobs. Using one where you need another is why servers either leak spam or drown moderators in false positives.
Layer 1: Discord AutoMod. Native, server-side, and it reads message content, which is the thing bots without the privileged Message Content intent cannot do. It blocks the message before anyone sees it. Set it up first, on every server, regardless of what bots you run.
You get, per server: up to 6 keyword rules, plus one each of spam, keyword-preset, mention-spam, and member-profile. Each keyword rule takes up to 1,000 keywords and up to 10 regex patterns, with up to 20 exempt roles and 50 exempt channels. Actions available are block the message, send an alert to a channel, time the member out, and block the member from interacting.
@Bond add an AutoMod rule blocking invite links, except for mods
Layer 2: bot automation on top of AutoMod. AutoMod firing is itself an event (automod_triggered). That is where escalation lives: log it, count it per member, and act when the count crosses a line. AutoMod blocks the message; your automation handles the fourth time the same person triggers it.
Layer 3: humans. Slowmode, timeouts, and judgement calls. Automation should hand moderators a clean queue, not replace them.
@Bond put a 30 second slowmode on #general for now
See configure AutoMod rules, moderation, and slowmode.
The limits, stated up front
This is the section that saves you an afternoon.
No keyword triggers in bot automation
Discord only sends message content to bots holding the privileged Message Content intent. Bond does not hold it. That means a bot automation cannot match on what a message said. A rule like "when someone types !rank, reply with their level" cannot run, because the content it compares against arrives empty.
Message triggers still work for everything that does not read text: counting messages, levelling, tracking who posts where, reacting to activity levels. What they cannot do is read the words.
Keyword-triggered automation belongs in Discord AutoMod. That is not a workaround, it is the correct home for it: AutoMod runs inside Discord, sees everything, and blocks before delivery.
Prefix commands do not exist
Same root cause. !rank, !ticket, !daily are all reading message text. If a bot cannot read message text, it cannot have prefix commands.
The replacement is real Discord slash commands, and it is a better tool: typed arguments, autocomplete, per-role access control, a confirmation step on anything destructive, and they show up in the command picker so people can discover them.
@Bond make a /ticket command that opens a private channel with the Support role
Free servers on Bond can keep 5 custom commands enabled, with higher caps on server plans. See custom slash commands and restrict a command to certain roles.
Recurring schedules cost money, events do not
On Bond, event-triggered flows and one-time scheduled reminders are free. Recurring cron and interval schedules need a server plan, and a free server can keep 3 event flows enabled at once. An interval takes a whole number of seconds, from 1 second up to 86400, which is 24 hours; it runs on that gap rather than being rounded to a clock minute, so sub-minute intervals are accepted even though they are rarely what you want. See pricing.
This is worth designing around rather than against. Plenty of things people build as a schedule are better as an event anyway: "check every hour whether anyone new joined" is a member_join trigger.
Automation that fails repeatedly gets switched off
Any automation platform worth using disables a flow that keeps failing, rather than retrying into a rate limit forever. Bond tracks consecutive failures with the same signature and disables the flow when the streak continues; a healthy run clears it. Practical consequence: if an automation "just stopped", check whether it was disabled after failing, usually because a channel it posts to was deleted or renamed.
Bots cannot outrank the hierarchy
An automation that assigns a role only works if the bot's own role sits above that role. This is the most common reason a welcome flow greets people and then silently fails to give them the role. See Discord permissions explained.
Testing checklist
Before you call an automation done:
- Trigger it for real. A second account for join flows, a real reaction for reaction flows.
- Check the role actually landed, not just that the message posted.
- Check the timezone on anything scheduled, by setting it 5 minutes out first.
- Check what happens on the unhappy path. What does the automation do if the channel is deleted? If the member leaves before it finishes?
- Confirm the closing half exists for anything timed.
- Write down what you built. Six months later, "why does the bot post this every Monday" should have an answer.