comparison

a neutral map of popular telegram bot libraries. the short version: choose yaebal when you want type flow, generated contexts, first-party plugins and production tooling in one stack — and gramio is the closest relative in spirit, not a strawman.

methodology. versions are live npm dist-tags.latest lookups at time of writing. capability rows are checked against each project's own docs, changelogs and GitHub releases — not memory or guesswork — with a citation-worthy fact behind every ✅/❌. ⚠️ means we looked and either found mixed signals or nothing conclusive either way; it is not a quiet ❌. found something outdated or wrong? open an issue.

versions compared

libraryversion
yaebal0.1.x (pre-1.0)
grammY1.44.x
gramio0.12.x
puregram3.6.x
telegraf4.16.x

summary

librarybest attradeoff
yaebaltype-accumulating composer, generated context shortcuts, broad first-party plugin catalog, playground, tests, Bot API 10.1pre-1.0, newer ecosystem, smaller community
gramiothe closest architectural relative — type-accumulating composer via .extend(), generated contexts, its own test package, Bot API 10.0no colon-delimited filter-query DSL; smaller first-party plugin catalog outside the core patterns
puregramcodegen'd per-update context classes, type-accumulating .extend(), concurrency + per-chat ordering built into its polling transportno official scaffolder or test framework; plugin dependencies are checked at runtime, not compile time
grammYlarge plugin ecosystem, mature docs, official multi-worker concurrent runner, filter queries (the pattern yaebal borrows), Bot API 10.1 — tied with yaebalcontext typing needs a manually-declared "flavor" instead of auto-accumulating; no generated per-update context shortcuts
telegrafthe most widely used, huge base of examples and answers, official scaffolderweakest native TypeScript story of the five — custom context types are mostly manual, and its own release history shows no Bot API version bump since the 7.x era

feature matrix

featureyaebalgrammYgramiopuregramtelegraf
type-accumulating context⚠️
grammY needs a hand-written "context flavor" generic to get typed custom properties. gramio's and puregram's own docs both describe the same idea yaebal uses — `.extend(plugin)` accumulates types automatically, no casting — confirmed directly from their docs, not guessed. telegraf typically wants a manually-specified custom context type, a well-known pain point in its own GitHub discussions.
generated per-update context shortcuts
gramio (`@gramio/contexts`) and puregram (its update classes are codegen'd from the schema, ~30 discriminated subclasses) both do this too — yaebal isn't alone here. grammY uses one `Context` class with optional fields instead.
filter queries narrow the type ("message:text")⚠️
grammY popularized this exact colon-delimited pattern — it's the library yaebal credits the idea to. puregram's codegen'd `hasX` predicates and filters narrow types the same way. gramio narrows by event/update name through its composer instead of a colon-delimited query string — a related but different mechanism; we didn't confirm an equivalent to the specific "message:text" style. telegraf's `bot.on(...)` doesn't narrow the context type.
plugin dependencies checked before your code even runs✅ compile time⚠️⚠️ compile time (implicit)⚠️ runtime
yaebal's `Plugin<In, Out>` makes installing a plugin before its dependency a TypeScript error. gramio's own docs warn "order matters" for `.extend()` chains — using a not-yet-added property is almost certainly also a compile error there, just via natural type accumulation rather than a plugin declaring its own explicit input requirement. puregram has a named `dependsOn: ['session']` mechanism, but per its own docs it throws `PluginMissingDep` when the installer runs — a runtime check, not a type error. we found no equivalent in grammY or telegraf.
first-party test framework⚠️
@yaebal/test and GramIO's own `@gramio/test` are close equivalents — both wrap the bot, give you virtual users/chats (`createUser`/`createChat`), intercept outgoing api calls, and let you mock responses (`onApi`) without a real network call. grammY documents test hooks but, by its own community's account, no dedicated test framework exists yet. we found no first-party equivalent for puregram or telegraf.
official concurrent runner (ordered per chat)⚠️✅ built in⚠️
@grammyjs/runner scales across multiple workers on separate cores, with `sequentialize` enforcing per-chat order — a mature, well-documented equivalent to @yaebal/runner. puregram bakes the same idea into its own polling transport: a `concurrency` limit plus `sequentializeBy`, no separate plugin needed. we found no first-party equivalent documented for gramio or telegraf (community middleware may exist for either).
official scaffolding CLI
create-yaebal, @grammyjs/create-grammy, create-gramio and telegraf's own create-bot are all official, maintained scaffolders. we found no equivalent for puregram.
in-browser playground on the docs site
yaebal's docs run examples against mock Telegram updates in-browser. we checked each project's own docs site directly and found no first-party equivalent for any of the four — telegraf's community links out to generic third-party sandboxes (RunKit, CodeSandbox) instead.
zero-dependency, fetch-first core (edge runtimes)⚠️⚠️⚠️
grammY ships official hosting guides for Cloudflare Workers — both a Deno-native and a Node-compat version. gramio advertises Node/Bun/Deno support in its own tagline, but we found no dedicated Cloudflare Workers guide to confirm edge fetch-handler support specifically. we found no confirmation either way for puregram or telegraf.
Bot API freshness✅ 10.3✅ 10.1✅ 10.0⚠️
yaebal regenerates from Telegram's schema on a scheduled job. grammY's own release notes show Bot API 10.1 support — tied with yaebal. gramio's own changelog announced Bot API 10.0 "ecosystem-wide", one point release behind. the newest explicit Bot API version we could find mentioned in puregram's release history is 7.1, with nothing more recent confirmed either way. telegraf's own GitHub releases show no Bot API bump past the 7.x era, while the spec has since moved to 10.3 — expect real gaps in newer methods and fields.

why yaebal

typed-chain.ts
const bot = createBot(token)
  .install(session({ initial: () => ({ count: 0 }) }))
  .derive(async (ctx) => ({ user: await loadUser(ctx.from?.id) }))
  .on("message:text", (ctx) => {
    ctx.session.count;
    ctx.user;
    ctx.text;
    ctx.react("🔥");
  });
feature-routes.ts
import { Composer, createBot, filters } from "yaebal";

const support = new Composer()
  .filter(filters.regex(/^ticket (.+)$/i), (ctx) =>
    ctx.reply(`ticket created: ${ctx.match[1]}`),
  );

const bot = createBot(process.env.BOT_TOKEN!)
  .extend(support)
  .command("help", (ctx) => ctx.reply("send: ticket <subject>"));

bot.start();
  • the bot class extends the composer class, so there is one middleware engine.
  • derive, decorate, install and extend carry context types forward.
  • plugin dependencies are explicit and type-checked.
  • generated contexts add schema-derived shortcuts such as ctx.react().
  • @yaebal/test gives virtual users/chats and intercepted api calls for ci.
  • production packages cover retry, throttling, runner, webhooks, broadcasts and panels — a broader first-party catalog than any of the four above ship together.

when another library is reasonable

  • choose gramio if your team already uses it — it's the closest match architecturally (type-accumulating .extend(), generated contexts, its own test framework), and the choice mostly comes down to plugin catalog and docs style.
  • choose puregram if you want built-in per-chat-ordered concurrency without a separate runner package, or prefer its plugin/dependency style — just know that dependency ordering fails at runtime, not compile time.
  • choose grammY if you need its large existing plugin ecosystem today, or its official multi-worker concurrent runner is exactly what you already know — its Bot API coverage is current, tied with yaebal.
  • choose telegraf for legacy projects where migration cost dominates type-safety gains, or where the sheer volume of existing examples and answers matters more — but verify any newer Bot API feature you need is actually supported first; its own release history shows no version bump past the 7.x era.

migration paths