Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 2 min read

Why we ditched Discord Embeds for Components V2 (and built a minimalist bot)

If you've used Discord in the past few years, you've probably noticed that almost every bot feels identical: giant colorful embeds, endless emojis, noisy confirmation messages, and clunky reaction-based menus. When buil

If you've used Discord in the past few years, you've probably noticed that almost every bot feels identical: giant colorful embeds, endless emojis, noisy confirmation messages, and clunky reaction-based menus.

When building ego β€” a curated social utility bot β€” we decided to take a completely different route: keep it minimal, understated, and built entirely around Discord Components V2.

Here is why we moved away from classic embeds and how we structured the architecture.

The Problem with Traditional Embeds

Classic Discord embeds were great in 2017, but today they have major UX flaws:

  1. Visual noise: High-contrast colored sidebars draw unnecessary attention to trivial status messages.
  2. Screen real estate: A simple command response can take up half a phone screen.
  3. Impersonal feel: They look like automated marketing bots rather than natural platform utilities.

Discord markdown has evolved. Features like subtext, blockquotes, and native Components V2 (containers, sections, buttons, and separators) allow you to build interfaces that feel native to Discord's dark theme.

Instead of big colorful banners with decorative emojis, clean status blocks like this look significantly better:

ws: 16ms
-# shard 0 Β· 14 guilds

Tech Stack Choices: Pragmatism Over Hype

For ego's core architecture, we opted for:

  • Runtime: Node.js 22 + TypeScript (ESM)
  • Library: discord.js v14
  • Database: SQLite with better-sqlite3 and drizzle-orm
  • Cache / Hot-State: Optional Redis layer, falling back to in-memory

Why SQLite + Drizzle?

A lot of bot developers immediately spin up PostgreSQL or MongoDB. For a social utility bot handling local guild preferences, fast identity histories, and low-latency lookups, an embedded SQLite database running with WAL mode (Write-Ahead Logging) delivers sub-millisecond query times with zero networking overhead.

export const userSnapshots = sqliteTable('user_snapshots', {
  id: text('id').primaryKey(),
  userId: text('user_id').notNull(),
  username: text('username').notNull(),
  avatarHash: text('avatar_hash'),
  capturedAt: integer('captured_at', { mode: 'timestamp' }).notNull(),
});

───

Killer Feature: Frictionless Media Auto-Resolution

One of the biggest pain points in modern Discord is broken video previews when someone pastes a link from Instagram, X (Twitter), or TikTok.

Rather than making users run commands like /fixlink or paste alternative domains, ego listens passively for supported URLs:

  1. Resolves the direct media source via backend streamers.
  2. Attaches the video/photo directly using native Discord message attachments.
  3. Suppresses the original broken embed using MessageFlags.SuppressEmbeds.

The result: users get instant playable video right in their feed without clutter or friction.

───

What We Learned

  1. Restraint is a feature: Removing information is harder than adding it, but users appreciate tools that don't shout for attention.
  2. Components V2 are the future of Discord UI: Separators, accessory thumbnails, and discreet button rows provide significantly better hierarchy than legacy embeds.
  3. Keep feature logic out of generic event files: Isolate features into dedicated modules with their own lifecycle hooks and services.

You can check out the live project at ego.skin (https://ego.skin).

How are you approaching UI design in Discord applications in 2026? Are you still using embeds or transitioning to components? Let me know in the comments!

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.