DEV Community

Cover image for How One User's Status Pinged My Entire Discord Server
Mohammad Amaan
Mohammad Amaan

Posted on • Originally published at npmjs.com

How One User's Status Pinged My Entire Discord Server

Every Discord bot eventually gets the same feature request:

"Can I customize the welcome message?"

Seems simple enough. An admin wants to write something like:

Welcome {user} to {server}! You're member #{count}.
Enter fullscreen mode Exit fullscreen mode

and your bot fills in the blanks.

The first version I built looked exactly like you'd expect:

const msg = template
  .replaceAll("{user}", `<@${member.id}>`)
  .replaceAll("{server}", guild.name)
  .replaceAll("{count}", String(guild.memberCount));
Enter fullscreen mode Exit fullscreen mode

Honestly, it felt done.

Then reality showed up.

A server owner wanted premium members to get a different welcome message. Another wanted to display the user's roles. Someone else wanted conditional content. Then eventually a user managed to get @everyone into a piece of user-generated content, and suddenly my bot was helping ping thousands of people.

That was the moment I realized something important:

replaceAll() is a string replacement tool. A templating system is a parser.

Those sound similar until you start adding features. Once users can write their own templates, you're no longer replacing text — you're interpreting a language. That means you need things like validation, conditionals, loops, nesting, escaping, and error handling.

After solving this problem repeatedly across Discord projects, I ended up building a small library called tagparse.

It's not trying to replace Handlebars, Mustache, or EJS. It's designed specifically for chat applications where users expect syntax like {user} and where mistakes can accidentally ping entire servers.

This post walks through building a proper welcome-message system using tagparse, including:

  • Variables
  • Conditionals
  • Loops
  • Mention-safe escaping
  • Template validation

By the end you'll have a welcome-message system that's significantly safer than a chain of replaceAll() calls and only slightly more code.

Full disclosure: I wrote tagparse. This article is about the problem that motivated it, and the library happens to be the solution I ended up building.

Why Not Just Use Handlebars?

Whenever I show this library to someone, the first question is usually:

"Why not just use Handlebars?"

That's a reasonable question.

Handlebars and Mustache are mature, battle-tested tools. If you're rendering HTML, I'd probably recommend them before anything else.

The issue is that Discord bots aren't HTML applications. The things bot developers care about are different:

  • User mentions
  • Role mentions
  • Channel references
  • Timestamp formatting
  • Preventing @everyone abuse
  • Dashboard-friendly syntax

Most Discord users already expect placeholders to look like:

{user}
{server}
{count}
Enter fullscreen mode Exit fullscreen mode

not:

{{user}}
{{server}}
{{count}}
Enter fullscreen mode Exit fullscreen mode

Matching what users already know turns out to matter more than I originally thought.

The second issue is safety. Traditional template engines understand HTML injection because that's the environment they were built for. They don't understand Discord mention injection.

To Handlebars, @everyone is harmless text. To a Discord bot, it can be a support ticket waiting to happen.

That's the gap tagparse tries to fill.

Top comments (0)