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)