Telegraf is one of the important community projects in the Telegram bot ecosystem. It has been around for years, it has a clean programming model, and many Node.js bots still depend on it.
But the Telegram platform has not stood still. The official Bot API has kept moving, while Telegraf’s mainline updates have slowed down. That gap matters more now than it did a few years ago. Telegram is no longer only a place for simple command bots. It is increasingly a practical interface for AI agents: private chats, group coordination, media input, inline workflows, web app handoffs, notifications, and long-running assistant loops.
If a framework does not keep up with the upstream API, every serious bot starts paying the tax locally. Developers patch missing methods, copy new Telegram types into application code, work around outdated examples, or avoid newer features entirely. That is not a good base for agent systems, and it is not a good outcome for a project as widely used as Telegraf.
So I forked the project and started a larger modernization pass toward v6. The main pull request is telegraf/telegraf#2092. The companion type-definition work is telegraf/types#14. The docs follow-up is feathers-studio/telegraf-docs#23.
What v6 is trying to do
This is not a rewrite for the sake of rewriting. Telegraf’s existing model is
still good: middleware, context helpers, Composer routing, scenes, sessions,
and the low-friction bot.command / bot.on style are all worth preserving.
The goal of v6 is to make that model current again:
- align Telegraf with Telegram Bot API 9.6;
- expose runtime wrappers for the official API surface;
- use
@telegraf/typesas the source of truth for future Bot API syncs; - modernize the runtime baseline around Node.js 20 and native platform APIs;
- remove stale compatibility assumptions that made the networking layer harder to maintain;
- add tests that make future API drift visible instead of silent.
The most important design choice is to keep future Bot API updates mechanical. The type package should describe Telegram’s canonical API. Telegraf should then wrap every typed method it can support, and tests should fail when the runtime falls behind the declarations. That turns “someone should check the changelog” into a concrete maintenance workflow.
Catching up with the Bot API
The v6 branch updates Telegraf for the current Bot API generation and adds
coverage around the newly typed surface. The tests now inspect
@telegraf/types and verify that Telegram has wrappers for the official
methods. This is a small but useful guardrail: once the type package moves, the
runtime can no longer quietly miss a method.
Newer request shapes also exposed a multipart edge case. Some Bot API payloads
can contain nested InputFile values, so the upload serializer now handles
those recursively. That is the kind of detail that tends to break only after a
real bot starts using a new Telegram feature. It is better to cover it in the
framework.
The types work is currently staged through the companion PR. Until it lands
upstream or is published as an official package, the Telegraf PR temporarily
points at my @telegraf/types fork. That is not the final desired dependency;
it is only a way to validate the runtime against the actual Bot API 9.6 shape
while the upstream review is happening.
Modern Node, less baggage
The networking layer changed more than I first expected. Older Telegraf releases
depended on node-fetch and exposed node-fetch-specific agent options such
as telegram.agent and telegram.attachmentAgent. That made sense in older
Node versions, but it is no longer the right default for a modern Node.js
runtime.
Telegraf v6 uses the native globalThis.fetch by default. It no longer bundles
node-fetch, and the old agent hooks are replaced by a more general extension
point: inject your own telegram.fetch.
The important part is not the specific fetch implementation. Users can still bring the networking behavior they need for proxies, custom TLS, compression, logging, or special deployment environments. Telegraf just needs one clean hook, and that same hook is used for both Bot API calls and URL attachments.
The Node.js baseline also moved to Node 20. That allowed the codebase to remove older runtime shims and update supporting tools such as the timeout path, lint configuration, tests, and release workflow. A major version is the right place to do that. Keeping a modern framework tied to old platform assumptions makes every future change more expensive.
Tests as a maintenance contract
The branch is not only a pile of wrappers. I spent a lot of time making the tests describe the intended maintenance contract:
- Bot API methods declared by
@telegraf/typesmust be represented at runtime; - newer Bot API fields should be visible in the generated type surface;
- custom fetch must work for normal API calls;
- custom fetch must also work for URL attachments;
- request timeout behavior must abort fetch calls cleanly;
- multipart form data must preserve nested
InputFilepayloads; - webhook rejection behavior must return useful HTTP status codes and headers.
The current Telegraf test suite passes with 180 tests. The package also builds, lints, generates TypeDoc output, and passes an npm pack dry run. There are still TypeDoc warnings, but they are warnings in the generated reference surface, not failing runtime behavior.
The documentation had to move too
Modernizing the code without updating the docs would leave users with the old mental model. That is why I also opened a documentation PR against feathers-studio/telegraf-docs.
The docs update does a few practical things:
- explains the new native
globalThis.fetchdefault; - replaces old proxy examples based on
telegram.agentwithtelegram.fetch; - updates the context options shape to include
fetchandrequestTimeout; - refreshes examples that were stale against newer Bot API typings, such as
thumbnail_url,correct_option_ids, andtelegraf/typesimports; - fixes framework-specific webhook examples for Fastify and Koa;
- moves the AWS Lambda example to the Node.js 20 runtime.
I did not open a separate PR against the upstream gh-pages branch. That branch
contains generated TypeDoc output for the published site. The right path is to
land the source changes, then let the release workflow regenerate the site from
the upstream repository when v6 is tagged. Manually editing generated HTML would
create a large diff with very little review value.
Why this matters now
Telegram is a surprisingly good surface for AI systems. It already has identity, contacts, groups, rich media, push notifications, inline interactions, and mobile clients that people actually use. For agents, that makes Telegram a natural place to receive instructions, ask follow-up questions, send files, and coordinate with humans.
But agent-facing infrastructure needs boring reliability. Missing API coverage, stale types, and outdated networking assumptions are exactly the small cracks that become annoying in production. A framework like Telegraf should make the common path simple while still giving advanced users room to customize the edge cases.
That is the v6 direction: keep the Telegraf programming model, catch up with Telegram’s official API, modernize the runtime, and make future API updates less heroic.
Current status
At the time of writing:
- the main Telegraf v6 PR is open as telegraf/telegraf#2092;
- the Bot API 9.6 types PR is open as telegraf/types#14;
- the documentation PR is ready for review as feathers-studio/telegraf-docs#23.
The work is intentionally staged. First the official type surface needs to be
accepted or published. Then the main Telegraf dependency can switch back from
the temporary fork to the official @telegraf/types release. After that, the
docs can point at the published telegraf@^6.0.0 package instead of the stacked
branch.
That is a bit of coordination, but it is the kind that makes an open source upgrade reviewable. Types, runtime, tests, release notes, and examples each have their own place, and the final result should be a Telegraf line that is much easier to keep current with Telegram from here.