node-telegram-bot-api

A runtime-agnostic, fully-typed TypeScript client for the Telegram Bot API, with middleware routing, sessions, and zero dependencies.

SDK
npm
v2.1.0
9,203stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
88/100Excellent
Development Activity100
Maintenance72
Community80
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
93/100Excellent
Architecture92
Code Quality95
Innovation85
Learning Curve100

node-telegram-bot-api v2 is a from-scratch rewrite of the long-running Node.js Telegram bot client, built as a web-standard TypeScript SDK that runs unmodified on Node.js, Bun, Deno, Cloudflare Workers, and Vercel Edge Functions. At its center is a Bot composition root with koa-style middleware (use/on/command/hears) dispatching through a single handleUpdate path shared by long-polling and webhooks, alongside an Api client that mirrors the Telegram Bot API 1:1, one method per endpoint.

The library ships builders for inline/reply keyboards, rich-text entities, media groups, and sticker sets; a pluggable session layer with in-memory, file, SQLite, Redis, and SQL-backed stores; streaming file uploads that keep memory flat regardless of size; and adapters for Express, Next.js App Router, Cloudflare Workers, and a self-hosted Node webhook server. The transport layer handles retries, exponential backoff, 429 flood-wait handling, and optional proactive rate limiting, surfacing failures through a structured error hierarchy instead of untyped exceptions.

What You Get

  • A Bot class with use/on/command/hears middleware routing and a single handleUpdate dispatch path shared by polling and webhooks
  • An Api client that mirrors the Telegram Bot API method-for-method, each call taking one typed params object
  • Builders for inline/reply keyboards, rich-text entities, media groups, and sticker sets that serialize to plain Telegram payload shapes
  • A pluggable session middleware with in-memory, file, SQLite, Redis, and SQL store adapters, plus a reply-tracking layer built on top of it
  • Streaming file uploads (InputFile, fromPath) that keep memory flat on large uploads and replay safely on retry
  • Webhook adapters for Express, Next.js App Router, Cloudflare Workers/Bun/Deno, and a self-hosted Node HTTP server
  • A resilient transport with automatic retries, exponential backoff, 429 retry_after handling, and optional proactive per-chat rate limiting
  • A structured error hierarchy (NetworkError, TimeoutError, ParseError, TelegramApiError) instead of untyped throws

Common Use Cases

  • Building a command-driven Telegram bot (support bot, notification bot, admin utility) with bot.command() routing
  • Running a bot on Cloudflare Workers or Vercel Edge Functions via the web-standard webhookCallback
  • Building multi-step conversational flows with the session middleware and reply-tracking to know which prompt a reply answers
  • Calling the Telegram Bot API directly (e.g. from a backend job) via the standalone Api client without running a bot loop
  • Sending media-rich messages - photos, documents, media groups, and inline/reply keyboards - built with the included builders

Under The Hood

Architecture The library is layered as types (generated, exhaustively-typed Update/Bot-API schemas) under core (the Node-free, edge-safe engine: Bot, Api, Transport, Context, compose) under node/bun (runtime-specific adapters - file-based sessions, webhook servers, SQLite/Redis stores). Bot is the composition root: it holds one Api, an ordered middleware array, and an error boundary, dispatching every update through a single handleUpdate path that both startPolling() and webhookCallback funnel into, so polling and webhook delivery can never diverge in behavior. Transport is deliberately the only module that touches fetch, injectable via options.fetch for testing, and owns retry/backoff/429 handling behind a typed request<R>() call. Registration-order middleware composition (compose.ts) is a small, dependency-free koa-compose reimplementation, and on/command/hears are themselves middleware wrappers pushed onto the same chain rather than a separate routing system, so a session or auth middleware registered via use() wraps everything downstream uniformly.

Tech Stack Written entirely in TypeScript with zero runtime dependencies, built with zshy into dual ESM/CJS output plus a dedicated Bun-targeted build (tsconfig.bun.json), and linted/formatted with Biome. Tests run under Bun’s native test runner and, in parallel, under node:test via tsx, so the suite is verified on two runtimes in CI. A custom scripts/check-core-imports.mjs enforces that src/core never imports a node:* module, and scripts/check-edge-bundle.mjs verifies the core bundle stays edge-runtime-safe - both run as CI gates, not just conventions. Webhook adapters target Express, Next.js App Router, and native Node http, while store adapters cover SQLite, Redis, and generic SQL for session persistence.

Code Quality The test suite spans roughly twenty files and thousands of lines covering routing, transport retries, encoding, sessions, webhooks, and rate limiting, with a dedicated test/e2e suite that can run against the live Telegram API. Error handling is fully typed: every failure mode (network, timeout, parse, Telegram API error) is a distinct TelegramBotError subclass with structured fields (errorCode, retryAfter) rather than string-matched messages, and an isTransientError helper centralizes retry classification. CI runs tsc --noEmit separately for src, test, and examples, alongside the core-isolation and edge-bundle checks, so a change that leaks a Node dependency into core or breaks the public examples fails the build.

What Makes It Unique Most Telegram bot libraries in this space target Node.js only; this one treats Node as just one of several first-class runtimes (Bun, Deno, Cloudflare Workers, Vercel Edge), unifying them behind a single web-standard (Request) => Promise<Response> webhook contract and an injectable-fetch transport. The per-update dispatch tables in Context (mapping every update variant to its chat/from resolver) are typed so that adding a new Telegram update kind is a compile error until every table has a matching row, giving exhaustiveness guarantees uncommon in hand-rolled SDKs. The opt-in reply-tracking layer, built strictly on top of the session middleware rather than in-memory promises, lets multi-step conversations survive process restarts and work correctly under one-invocation-per-update serverless execution.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search