node-telegram-bot-api@2.0.0 is out (release notes). We are on ^1.2.0 (1.2.0 installed). This issue tracks the move.
This is not a dependency bump. The upstream release describes itself as "a from-scratch redesign with no backward compatibility with the v1 TelegramBot surface". Treat it as a rewrite of our transport layer, planned and executed in steps — not as a Dependabot PR to merge.
Requirements
What v2 changes upstream
From the release notes:
| Area |
v1 |
v2 |
| Class |
TelegramBot |
Bot |
| Method calls |
positional — bot.sendMessage(chatId, text, opts) |
single params object — bot.api.sendMessage({ chat_id, text, … }) |
| Update handling |
event emitter — bot.on('message') |
koa-style middleware |
| Text matching |
bot.onText() |
bot.hears() |
| Reply hooks |
bot.onReplyToMessage() |
middleware reading ctx.message.reply_to_message |
| Webhook |
bot.setWebHook() positional |
bot.api.setWebhook({}) |
| Polling state |
bot.isPolling() |
bot.isRunning() |
| Errors |
EFATAL |
split into NetworkError and TimeoutError |
| Uploads |
streams/buffers |
InputFile + fromPath(), streaming without full buffering |
| Keyboards |
JSON strings |
plain typed objects |
| Module format |
CJS |
dual ESM + CJS, Node-specific utilities under node-telegram-bot-api/node |
| Engine |
— |
Node >= 18 (we are already at >= 22.19, so no constraint) |
New surface worth noting: rich messages (InputRichMessageMedia, InputRichBlock), ephemeral message methods, communities, subscription updates.
Analysis to do first (before implementation)
Breaking-change impact per file. Rough size of the blast radius, by matches on the affected APIs:
| File |
Hits |
What lives there |
telegrambot/nodes/bot-node.js |
33 |
bot construction, polling/webhook lifecycle, listener wiring, restart logic |
telegrambot/nodes/out-node.js |
6 |
the send path |
telegrambot/lib/undici-pool.js |
3 |
per-bot dispatcher via request.fetchOptions |
telegrambot/nodes/control-node.js |
2 |
setWebHook / deleteWebHook |
telegrambot/nodes/reply-node.js |
2 |
reply handling |
Questions the analysis has to answer:
Candidates for deletion rather than porting
Things we built because v1 lacked them. Each needs a yes/no answer, and a no means the code goes:
Existing issues to re-check
Required by this issue; first pass only, each still needs a real review:
- #459 Tier 1, #460 Tier 2, #461 Tier 3, #462 Tier 4 — all four are "implement Bot API method X" issues from 2026-06-17, written against the v1 surface. v2's uniform
bot.api.* namespace likely changes both the effort and the tiering: some may collapse into "already reachable", others may need re-scoping. Do not implement any of them against v1 before this decision is made — that work would be thrown away.
- #498 — npm-bundled advisories. Unrelated to v2; leave open.
Suggested step plan
Refine after the analysis; the point is that no step is a big-bang.
- Spike, throwaway. Build one
Bot, send one message, run one update through middleware. Answers the dispatcher and CJS questions cheaply.
- Write the analysis into an ADR (breaking changes for us, what dies, what survives).
- Isolate the transport. Put the v1 surface behind a thin internal seam so nodes stop calling the library directly.
- Port the seam to v2 behind the same interface, with the suite green.
- Port node by node — out, reply, control, event, receiver — one commit each.
- Delete what v2 made redundant (the list above), each removal its own commit.
MIGRATION.md + ADR + major bump, then release.
Steps 1–2 are the gate: if the spike says the dispatcher hook is gone, this stops and gets re-planned rather than continuing.
node-telegram-bot-api@2.0.0is out (release notes). We are on^1.2.0(1.2.0 installed). This issue tracks the move.This is not a dependency bump. The upstream release describes itself as "a from-scratch redesign with no backward compatibility with the v1
TelegramBotsurface". Treat it as a rewrite of our transport layer, planned and executed in steps — not as a Dependabot PR to merge.Requirements
MIGRATION.mdgets a "Migrating to V20.0.0" section, in the same shape as the V18 entry. Whatever cannot be shimmed must be spelled out with before/after examples.What v2 changes upstream
From the release notes:
TelegramBotBotbot.sendMessage(chatId, text, opts)bot.api.sendMessage({ chat_id, text, … })bot.on('message')bot.onText()bot.hears()bot.onReplyToMessage()ctx.message.reply_to_messagebot.setWebHook()positionalbot.api.setWebhook({})bot.isPolling()bot.isRunning()EFATALNetworkErrorandTimeoutErrorInputFile+fromPath(), streaming without full bufferingnode-telegram-bot-api/nodeNew surface worth noting: rich messages (
InputRichMessageMedia,InputRichBlock), ephemeral message methods, communities, subscription updates.Analysis to do first (before implementation)
Breaking-change impact per file. Rough size of the blast radius, by matches on the affected APIs:
telegrambot/nodes/bot-node.jstelegrambot/nodes/out-node.jstelegrambot/lib/undici-pool.jsrequest.fetchOptionstelegrambot/nodes/control-node.jssetWebHook/deleteWebHooktelegrambot/nodes/reply-node.jsQuestions the analysis has to answer:
undiciAgentto Node's built-infetchthroughrequest.fetchOptions. Does v2 still expose a transport hook of that shape? This decides whether SOCKS proxy support and the Connection to TG break after weeks #442 keep-alive defence survive the port — if v2 drops the hook, that is a blocker, not a detail. Check before anything else.fetch, the ignore rule on undici majors may become liftable — or moot.EFATALsplitting intoNetworkError/TimeoutErrortouchestelegrambot/lib/error-chain.jsand the status/error surfacing in the nodes.msg.errorshapes are user-visible.node-telegram-bot-api/nodesubpath.Candidates for deletion rather than porting
Things we built because v1 lacked them. Each needs a yes/no answer, and a
nomeans the code goes:telegrambot/lib/legacy-options.js— the V18 compatibility shim rewriting deprecatedmsg.payload.optionsfields. With v2's params objects the mapping changes completely. Decide: carry it forward (rewritten), or drop it as part of the major and document the removal inMIGRATION.md.InputFile/fromPath()and streaming uploads may replace buffering we do ourselves.callApiescape hatch — its reason for existing is methods the library did not expose. Re-evaluate against v2'sbot.api.*surface, which appears to be complete and uniform.callApi(ephemeral messages, rich messages, communities, subscriptions) — v2 exposes them natively.Existing issues to re-check
Required by this issue; first pass only, each still needs a real review:
bot.api.*namespace likely changes both the effort and the tiering: some may collapse into "already reachable", others may need re-scoping. Do not implement any of them against v1 before this decision is made — that work would be thrown away.Suggested step plan
Refine after the analysis; the point is that no step is a big-bang.
Bot, send one message, run one update through middleware. Answers the dispatcher and CJS questions cheaply.MIGRATION.md+ ADR + major bump, then release.Steps 1–2 are the gate: if the spike says the dispatcher hook is gone, this stops and gets re-planned rather than continuing.