To host a node-telegram-bot-api bot 24/7 you run it on a machine that stays on: a Linux VPS with a systemd service that starts it again when it stops, or a bot plan on PlayNHost (from US$1.99 a month), where the panel installs your packages, gives your code the token and starts the bot again if it crashes. In our test a node-telegram-bot-api 2.3.0 bot used about 63 MB of memory on Node.js 22. One thing first: version 2, the one npm installs today, is a new library with no TelegramBot class, so tutorials written for older versions no longer match it. Bots written for 0.x or 1.x keep their API when you pin their version, as shown below. The steps on PlayNHost:
- On Telegram bot hosting, click Create Server on a plan. In the order window, answer What is your bot for? with Telegram and pick Node.js.
- Open your server in the panel. The Set up your bot card on Overview opens at Connect to Telegram; its first step, What runs, should say This bot runs Node.js Bot.
- At Connect to Telegram, paste the token from @BotFather under Paste your bot token, click Connect, check the bot name shown and click Yes, continue.
- Check that your
package.jsonnames the version your code is written for:^2.3.0for anew Bot(...)bot, or the old version for anew TelegramBot(...)bot. - At Your code, click Upload files and upload your
package.jsonandindex.jswithoutnode_modules, or click Connect Git. - On the Bot page, pane Code, check that Entry file is the file that starts your bot (
index.jsby default). Click Save if you change it. - Click Start bot and open Console. npm installs the library on the first start, then your bot prints
Logged in as @your_botand the chip on Overview turns to Online in Telegram. - On the Bot page, pane Telegram, click Open in Telegram and send your bot
/start.
Creating the bot in @BotFather and the panel steps are explained in How to host a Telegram bot. This page is about node-telegram-bot-api itself: its versions, what it uses on a server and what to know before you host it.
Which version is your bot written for?
The package name stayed the same, but its API changed completely in August 2026:
| Version | Released | Your code looks like |
|---|---|---|
| 0.x (last: 0.67.0) | Up to 13 Dec 2025 | const TelegramBot = require('node-telegram-bot-api'), new TelegramBot(token, { polling: true }), bot.onText(...), bot.sendMessage(chatId, text) |
| 1.x (1.0.0 to 1.2.0) | 12 Jun to 14 Jul 2026 | The same TelegramBot class, rewritten in TypeScript, loaded with import TelegramBot from 'node-telegram-bot-api' |
| 2.x (now 2.3.0) | From 16 Aug 2026 (2.3.0: 4 Nov 2026) | const { Bot } = require('node-telegram-bot-api'), bot.command(...), ctx.reply(...), bot.api.sendMessage({ chat_id, text }) |
The project's README says it plainly: "v2 is a from-scratch redesign, no v1 compatibility", and its changelog says that npm install node-telegram-bot-api from an old tutorial "now lands you on a completely different API". A TelegramBot bot started with 2.x fails at once, because the class no longer exists.
For a bot written for 0.x, keep that version in package.json:
"dependencies": {
"node-telegram-bot-api": "^0.67.0"
}
A ^ range never moves to a new major version, so the daily package install on our servers keeps your bot on 0.x. Do not write latest or *. If you install it through Packages on the Code pane instead, write the version too, node-telegram-bot-api@0.67: a name without a version asks npm for the release tagged latest, which is 2.3.0.
What we measured
| Library | Version | Memory at rest | Start to Telegram's answer | Install size |
|---|---|---|---|---|
| node-telegram-bot-api | 2.3.0 | 63 MB | 0.2 s | 2.4 MB |
| grammY | 1.46.0 | 60 MB | 0.2 s | 3.0 MB |
| Telegraf | 4.16.3 | 60 MB | 0.2 s | 2.7 MB |
| Node.js 22 alone, no library | 22.23.4 | 43 MB | none | none |
How: on our own node, in a throwaway container set up like a 1 GB bot plan (the Node.js 22 image and start command of our Node.js bot type, with Node's memory limit at 80 percent), each bot called Telegram with a fake token, which Telegram refused; memory is the resident memory 15 seconds after that answer, start time runs from launch to the answer, and each figure is the median of runs 2 to 4. We measured version 2; 0.x was not measured.
These are floors: a bot with no chats and no data yet. Your own code, what it keeps in memory and the number of chats add to them, so the library is a small part of the 0.5 GB STARTER plan.
A minimal node-telegram-bot-api 2 bot
It answers /start, reads the token the panel gives it and prints a ready line. Put both files in your bot's main folder.
package.json
{
"name": "my-telegram-bot",
"private": true,
"main": "index.js",
"dependencies": {
"node-telegram-bot-api": "^2.3.0"
}
}
index.js
const { Bot, TelegramApiError } = require("node-telegram-bot-api");
const { run } = require("node-telegram-bot-api/node");
const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN);
bot.command("start", (ctx) => ctx.reply("Hello! I am running on PlayNHost."));
async function main() {
await bot.init(); // asks Telegram who the bot is, so a wrong token fails here
await bot.api.deleteWebhook(); // version 2 does not remove a webhook by itself
console.log(`Logged in as @${bot.botInfo.username}`);
await run(bot); // polls for messages until the bot is stopped
}
main().catch((err) => {
if (err instanceof TelegramApiError && err.errorCode === 401) {
console.log("Telegram did not accept the bot token. Paste the current one from @BotFather, then restart.");
} else {
console.error(err);
}
process.exit(1);
});
The library's own examples read process.env.BOT_TOKEN. The panel gives your code the token as TELEGRAM_BOT_TOKEN and also as BOT_TOKEN, TOKEN, TELEGRAM_TOKEN and TELOXIDE_TOKEN, so those examples run without changes. run() comes from node-telegram-bot-api/node: it polls and stops cleanly on SIGINT or SIGTERM. Version 2 works with require as above or with import.
If the token is wrong
In our test, with a fake token, version 2's first call to Telegram (getMe) failed with this error:
TelegramApiError: 401: Unauthorized
Version 2 does not retry a refused token: bot.init() fails at once. The bot above catches that case and prints Telegram did not accept the bot token. Paste the current one from @BotFather, then restart. instead, and the panel shows the banner Telegram did not accept your bot token above Console. To fix it, in @BotFather send /mybots, choose your bot, then API Token, and copy the token again. On the Bot page, pane Telegram, click Replace token, paste it, click Save token, then Restart now.
A 0.x bot behaves differently: it does not stop. It logs a line such as error: [polling_error] {"code":"ETELEGRAM","message":"ETELEGRAM: 401 Unauthorized"} and asks Telegram again about every 0.3 seconds, so it looks running while nothing answers. The panel reads that line and shows the same banner.
What to know about node-telegram-bot-api on a server
- A webhook left on the bot: version 2 does not remove it. Its polling treats the
409as a conflict, retries 10 times, 5 seconds apart, then stops. The bot above callsbot.api.deleteWebhook()before it polls; you can also click Remove webhook on the Telegram pane. Version 0.x removes a webhook by itself when polling meets a409. - Another copy of the bot: on
409 Conflictversion 2 waits 5 seconds and tries again, quietly, up to 10 times in a row. After that it stops andrun()printsnode-telegram-bot-api: polling stopped on a fatal error:with Telegram's text, and the panel shows Your bot is running somewhere else too. Stop the copy on your PC or your old host. See Fix Telegram bot 409 Conflict. - An error in a command does not stop the bot. Version 2 prints
Unhandled error while processing updatewith the error and carries on. Set your own handler withbot.catch((err, ctx) => ...). - Webhooks:
startWebhook,createWebhookServerandwebhookCallbackneed a public HTTPS address, which these plans do not include yet. Userun(bot)orbot.startPolling(). Moving from a webhook host: How to move a Telegram bot to PlayNHost. - Seeing what it does: on the Bot page, pane Environment, add the variable
DEBUGwith the valuenode-telegram-bot-api:*(Add variable) and restart. Version 2 then traces each request and each poll to the console. - Node.js version: 2.3.0 needs Node.js 18.2 or newer. The Runtime on the Code pane offers Node.js 20, 22 (recommended), 24, 25 and 26.
- Memory limit: the start script sets
NODE_OPTIONS=--max-old-space-sizeto 80 percent of your plan's memory, so the rest of the process has room. Details of the Node.js start script: How to host a Node.js Discord bot.
Host it yourself on a Linux VPS
Version 2 needs Node.js 18.2 or newer. On Debian 12 or 13, or Ubuntu 24.04, the distribution's package is new enough (Debian 12 ships Node.js 18.20, Debian 13 ships 20.19, Ubuntu 24.04 ships 18.19); Ubuntu 22.04 ships Node.js 12, which is too old for it:
sudo apt update
sudo apt install nodejs npm
node --version
Make a user for the bot, copy your files and install the packages:
sudo useradd --system --create-home --home-dir /opt/mybot mybot
sudo cp package.json index.js /opt/mybot/
sudo chown -R mybot: /opt/mybot
cd /opt/mybot && sudo -u mybot npm install --omit=dev
Keep the token out of your code, in a file only root can read:
sudo sh -c 'echo "TELEGRAM_BOT_TOKEN=123456789:your-token" > /etc/mybot.env'
sudo chmod 600 /etc/mybot.env
Create /etc/systemd/system/mybot.service:
[Unit]
Description=node-telegram-bot-api Telegram bot
Wants=network-online.target
After=network-online.target
[Service]
User=mybot
WorkingDirectory=/opt/mybot
EnvironmentFile=/etc/mybot.env
ExecStart=/usr/bin/node index.js
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Start it now and at every boot, then follow its output:
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
sudo journalctl -u mybot -f
Restart=always starts the bot again after a crash or a process.exit(1). systemctl stop mybot sends SIGTERM, which run() turns into a clean stop. Stop any other copy first, or Telegram answers both with 409 Conflict.
Self-hosting or a bot plan
On a VPS you manage yourself:
- Operating system updates and security, and Node.js upgrades.
- Running
npm installafter each change, the service file, the token file and its permissions. - Reading
journalctlto find out why the bot stopped. - Backups of the bot's data.
In return a VPS runs anything, and you can give it a domain with HTTPS for a webhook.
On a PlayNHost bot plan the panel does this for you:
- A Node.js version picker, and
npm installwhenpackage.json, the lock file or the Node.js version change. - The token, checked with Telegram before it is saved, stored encrypted and given to your code.
- Starting the bot again after a crash. If it crashes again within a minute, it stays stopped and Console says why.
- Banners above Console that name the cause when Telegram refuses the token, another copy is running or a webhook is set, with a Remove webhook button on the Telegram pane.
- Upload, Git deploys and backups from the panel.
Questions people ask
My old bot stopped with an error such as TelegramBot is not a constructor. Why?
Most likely npm installed version 2, which has no TelegramBot class: require('node-telegram-bot-api') now returns an object of named exports such as Bot, not a class you can call with new. Put the version your bot was written for in package.json, for example "node-telegram-bot-api": "^0.67.0", delete node_modules and package-lock.json in Files, and restart: the packages install again. Or move the code to version 2 with the table in the project's changelog.
Should I write a new bot on version 2 or on 0.x?
For a new bot, version 2: it is the one that gets updates, and 2.3.0 supports Telegram's Bot API 10.3. Keep 0.x for an existing bot until you have time to move it; it still installs from npm.
Where do sessions survive a restart?
Not in MemorySessionStorage: it lives in the process and is empty after each restart. FileSessionStorage from node-telegram-bot-api/node writes one file per chat into a folder you name, for example ./.my_bot_sessions. On our plans that folder is in your server's files, so it survives restarts and is in your backups.
Ready to run your node-telegram-bot-api bot around the clock? See the plans on Telegram bot hosting.



