Telegram Serverless is Telegram's native environment for running backend code for bots and Mini Apps. Code executes on events in isolated V8 environments close to the Bot API; developers get a built-in SQLite database, outbound HTTP, and a CLI. tgcloud. VPS, containers, manual webhook setup, and separate credentials for the Bot API are no longer required.
The practical path has eight steps: enable Serverless in BotFather, create a project, sign in with a separate CLI token, review the diff, send modules with push, apply the schema with migrate, test the handler with the run command, and verify the webhook. But Telegram Serverless is not for everyone: the runtime works only with JavaScript modules, does not support npm packages or the file system, does not provide foreign keys, cannot yet upload new files from a handler, and accepts only text HTTP responses up to 32 MB.
Bottom line. Telegram Serverless is a good fit for event-driven bots, Mini App backends, integrations, and AI assistants that fit within a compact JavaScript runtime. VPS or an external cloud function is still better for Python, native dependencies, complex file processing, a custom database, and workloads with special resource requirements.
Contents
- What Telegram Serverless Is
- How It Differs from Standard Serverless
- How the Project Is Structured
- Launching Your First Bot in 8 Steps
- How Handlers Work
- Built-in Database
- Bot API and External HTTP
- Limitations
- Developing with an AI Agent
- Comparison with VPS and Cloud Functions
- Migrating an Existing Bot
- Production Checklist
- FAQ
- Conclusion
What Telegram Serverless Is
In the classic setup, Telegram sends an update to your webhook, and your server receives the event, runs code, and calls the Bot API. You have to rent or assemble the server from cloud functions, secure it, update it, scale it, and monitor it.
In Telegram Serverless, this backend runs on Telegram's own infrastructure. According to the official documentation, each invocation starts in a lightweight V8 isolate; Bot API, a SQLite database, and an HTTP client are available nearby. Developers keep source files locally and sync them to the cloud through tgcloud.
The useful model has four parts: event → module → data → action.
- Telegram receives a message, callback query, or other update.
- The platform calls the appropriate file in
handlers/. - The handler reads or changes state through
db. - The code responds through
apior calls an external service throughfetch.
This framework helps quickly check project compatibility. If the logic comes down to short reactions to updates and HTTP calls, the migration is realistic. If you need a long-running process, a custom OS, binary utilities, or a complex Python stack, one native environment will not be enough.
What It's Good For
Telegram describes four basic classes: conversational AI bots, Mini App backends, games and tools, and automations and integrations. In practice, this includes FAQ assistants, lead-generation bots, notifications, quizzes, task lists, Mini App dashboards, and CRM integrations over HTTP APIs.
For an AI bot, the built-in database stores user state, and streaming fetch handles token-by-token responses from an external model. When designing an enterprise agent, you still need your own access rules, spending limits, and safety checks for risky actions. The general approach is covered in the article "AI Agents in Business: Where They Work and Where It's Hype".
How It Differs from Standard Serverless
The name can be confusing. Before this product existed, Telegram bots were already running on AWS Lambda, Google Cloud Functions, Yandex Cloud Functions, and Cloudflare Workers. There, serverless refers to the cloud provider's execution model. Here, it is a separate native Telegram runtime.
The difference is not just hosting. The platform itself maps a Telegram update to a handler, exposes the Bot API without manually passing a bot token, provides a separate SQLite database for each bot, and manages the webhook. An external function, by contrast, gives you more languages and libraries, but you have to build the integration layer yourself.
As of July 17, 2026, the official page does not publish pricing, an SLA, CPU/RAM limits, or the maximum invocation duration. So claims like "free forever" or "suitable for any workload" are not verified. These parameters should be checked in BotFather and in the current terms before production.
How the Project Is Structured
The project consists of three types of JavaScript code:
handlers/ # entry points by Telegram update type
lib/ # shared project code
schema.js # table declarations
In the cloud, there is a deployed copy of the modules and a persistent database. The local folder remains the source of truth for the code, and the CLI shows differences and synchronizes states. On a full push the cloud copy mirrors the local set: a module deleted locally will also be deleted in the cloud.
Imports are written as bare names, without ./, ../ or the .jsextension:
import { api, db, fetch } from 'sdk';
import { users } from 'schema';
import { formatAnswer } from 'lib/format';
The runtime sees only sdk, its submodules, and the project’s custom modules. It has no npm packages, filesystem access, or direct network access outside the SDK fetch. This limitation reduces the execution surface, but it means dependencies must be rewritten in advance.
Launching Your First Bot in 8 Steps
You need Node.js 18 or newer and a bot registered with @BotFather. The CLI access token is different from the Bot API token: don’t mix them up and don’t commit secrets to Git.
1. Enable Serverless
Open BotFather → your bot → Serverless and turn the feature on. In the same section, handlers, library, database, and CLI Access become available.
2. Create a project
npm create @tgcloud/bot example_bot
cd example_bot
The scaffold creates a starter handler, schema.js, an empty lib/, the reference guide docs/tgcloud-sdk.md, the file AGENTS.md and package.json. The generator does not overwrite existing files.
3. Link the project to the bot
Get the token in BotFather → Serverless → CLI Access and run:
npx tgcloud login
The token has the form app<id>:<secret> and is stored in the git-ignored directory .tgcloud/. For CI, use the TGCLOUD_TOKEN environment variable; the CLI checks it first, then local credentials.
4. Review changes
npx tgcloud status
npx tgcloud diff
Both commands work offline by comparing the working files with a local reference copy of the cloud state.
5. Deploy the code
npx tgcloud push
Changed modules are sent as an atomic batch. If the cloud revision has already changed elsewhere, push will stop instead of overwriting a teammate’s work. In that case, use fetch, pull or an intentional push --force.
6. Apply the database schema
npx tgcloud migrate
push never changes the live database. It only deploys the new schema.js and shows pending changes; a separate migrate asks you to confirm safe, risky, and manual changes.
7. Test the handler without deploying
npx tgcloud run handlers/message '{ chat: { id: 1 }, text: "hello" }'
The command runs the local version of the modules on the platform, showing console.*, the result, and the duration. The payload is written in JSON5; the raw Update can be passed as a second context through --ctx.
8. Check the webhook
npx tgcloud webhook
npx tgcloud webhook sync
The platform manages the webhook and allowed_updates based on the set of deployed handlers. If they get out of sync, sync restores consistency; the --drop-pending flag also deletes any queued updates and should be used with caution.
How handlers work
Each update type gets its own file. handlers/message.js takes a Message object, handlers/callback_query.js takes a CallbackQuery. The platform strips the outer Update wrapper; the original object remains in ctx.update.
A minimal echo handler looks like this:
import { api } from 'sdk';
>
export default async function (message) {
await api.sendMessage({
chat_id: message.chat.id,
text:
You wrote: ${message.text ?? '(no text)'},
});
}
An update without a matching handler is ignored. This is more useful than a generic router: the bot receives only the update types it needs, and the project structure shows the real entry points. The full list of types is provided by the platform itself to the add command add.
Built-in database
Each bot gets its own persistent SQLite-backed database. The schema and query builder are similar to Drizzle ORM, but they are imported from sdk/db.
Message counter example:
// schema.js
import { table, integer } from 'sdk/db';
>
export const counters = table('counters', {
chatId: integer('chat_id').primaryKey(),
seen: integer('seen').notNull().default(0),
});
// handlers/message.js
import { api, db } from 'sdk';
import { counters } from 'schema';
import { sql } from 'sdk/db';
>
export default async function (message) {
const [row] = await db.insert(counters)
.values({ chatId: message.chat.id, seen: 1 })
.onConflictDoUpdate({
target: counters.chatId,
set: { seen: sql
${counters.seen} + 1},
})
.returning()
.run();
>
await api.sendMessage({
chat_id: message.chat.id,
text:
Messages in this chat: ${row.seen},
});
}
Supported types include TEXT, INTEGER, REAL, NUMERIC, BLOB, and convenient boolean/json modes. All queries are asynchronous: terminal methods return a Promise and require await.
Important limitation: no foreign keys
The runtime works with PRAGMA foreign_keys off. The DSL forbids .references() and foreignKey(), so developers do not rely on cascading behavior that does not work. Relationships are stored as regular ids, and integrity is enforced by application code: parent first, then children; when deleting, the reverse order; orphan records are checked with a separate query.
How migrations work
Changes are split into safe, warning, manual, and undocumented. Adding a table or index is usually safe; dropping requires separate confirmation; changing a column type remains manual. To remove a field or table, first mark it .deprecated('reason'), then confirm the drop in migrate.
Before production, npx tgcloud migrate --dry-run is useful. For CI, there is --safe, which automatically applies only safe changes. --yes confirms warnings too, so it should not be enabled without a fallback plan and review.
Bot API and external HTTP
Object api provides all current and future Telegram Bot API without upgrading the SDK. The call api.sendMessage(params) uses familiar snake_case parameters and returns result directly, without an envelope {ok, result}.
Errors are converted into BotApiError objects with code, description, method, and parameters fields. This lets you handle the expected 429 with retry_after separately and pass unknown errors through.
External HTTP is executed through the SDK fetch. It supports JSON, form, text, headers, and streaming reads for await (const chunk of res.body). The latter is useful for SSE and AI API tokens.
HTTP limitations are strict: the response must be text-based, binary payloads are not supported; the full response is limited to 32 MB. Streaming reduces memory usage during processing, but does not increase the overall limit.
Telegram Serverless limitations
| Limitation | What it means | Workaround |
|---|---|---|
| JavaScript modules only | A Python/Go backend cannot be moved over directly | keep an external service or rewrite the handlers layer |
| No npm packages | you cannot import Express, grammY, or arbitrary SDKs | use sdk, compact custom code, and HTTP APIs |
| No filesystem | you cannot store temporary files on disk | database, file_id from Telegram, or external object storage |
| No foreign keys | no cascades and no protection against orphan rows | application-level integrity and periodic checks |
| No downloading/uploading raw file bytes from a handler | the file pipeline is limited | reuse Telegram file_id or an external media service |
| HTTP response must be textual only | images/archives cannot be returned as bytes | the external service returns a URL or a Telegram file_id |
| HTTP response up to 32 MB | streaming does not remove the cap | pagination, chunks, response reduction |
| Price, SLA, and compute quotas are not published | TCO and capacity cannot be calculated from the documentation | check the current terms before production |
The last point matters for business. The absence of a server in your dashboard does not mean there are no infrastructure risks. Before launch, you need to understand the terms for data retention, backups, logs, support, quotas, and exportability.
Development with an AI agent
The new project includes AGENTS.md and the local reference docs/tgcloud-sdk.md. Telegram explicitly designs the scaffold so coding agents know the specific rules: bare imports, no foreign keys, async database calls, one handler per update type, and separate push/migrate.
The workflow looks like this: describe the feature in plain language, let the agent change schema.js and handlers, review the diff, run tgcloud run, inspect logs, and only then deploy. AI should not automatically run migrate --yes or push --force: both actions change external state and require review.
AGENTS.md should be updated together with the project: list domain entities, permitted external APIs, idempotency rules, error format, and prohibited operations. That way, AI generates code within the boundaries of the real system, not a generic Node.js template.
Telegram Serverless vs. VPS and Cloud Functions
| Criterion | Telegram Serverless | External Cloud Function | VPS/Container |
|---|---|---|---|
| Startup | minimal infrastructure | requires a cloud project and webhook | OS, deploy, TLS/webhook |
| Languages | JavaScript | depends on the provider | almost any |
| Dependencies | only the SDK and your own code | packages are usually available | full control |
| Database | built-in SQLite-backed | external managed storage | any database |
| Bot API credentials | included | store the bot token yourself | store the bot token yourself |
| Scalability | managed by Telegram | managed by the provider | designed by your team |
| Files and binaries | significantly limited | depends on the runtime | full control |
| Portability | locked to the Telegram runtime | locked to cloud APIs | higher with containers |
Choose Telegram Serverless, if your bot is event-driven, written in JavaScript, keeps moderate state, and talks to the outside world through JSON/text HTTP.
Choose a cloud function, if you need another language or package ecosystem, but do not want to administer a server.
Stay with a VPS/container, if you need workers, a queue, cron, binary utilities, heavy file processing, your own network, PostgreSQL, long-running jobs, or strict resource control.
How to migrate a bot from a VPS
Do not move everything in one deploy. Split the migration into seven verifiable stages.
- Inventory your update types. Make a list of message, callback_query, inline_query, and other entry points.
- Separate the Telegram layer from the domain logic. Each update gets a handler; shared logic moves to
lib/. - Review dependencies. For each npm/Python package, decide whether to rewrite it, replace it with an SDK call, move it to an external HTTP service, or drop it.
- Design the data model without foreign keys. Define the write and delete order, idempotency keys, and orphan checks.
- Migrate the data in a controlled way. The official page does not describe a universal import from an external database, so you need to validate the scenario for your specific data volume.
- Run the handlers through
run. Use real anonymized payloads and edge cases: duplicate update, 429, external API timeout, empty text. - Switch the webhook and monitor errors. Check
tgcloud webhook, pending updates, and rollback to the old backend.
The safest approach is to first move one non-critical handler. If it works reliably, move the other update classes and only then the data.
Production checklist
- [ ] Serverless is enabled for the required production bot; the test bot is separate.
- [ ] The CLI token and
TGCLOUD_TOKENdid not get into Git or logs. - [ ] For each handler, the behavior on repeated delivery of an update is defined.
- [ ] All
dbcalls haveawait; batch inserts are split to respect the SQLite variable limit. - [ ] Bot API errors and external 429s are handled explicitly.
- [ ] HTTP responses are text-based and guaranteed to be smaller than 32 MB.
- [ ] The file flow uses
file_idor an external media backend. - [ ] Relationship integrity is maintained without foreign keys.
- [ ] Before migration, run
migrate --dry-run. - [ ] The team knows when
pull,resetandpush --forceare allowed. - [ ] Webhook shows In sync, and the
allowed_updateslist matches handlers. - [ ] Price, quotas, SLA, backup/export, and data requirements have been confirmed separately.
FAQ
What is Telegram Serverless in simple terms?
It is a backend inside Telegram's infrastructure. You write JavaScript functions for message, callback query, and other updates, deploy them through tgcloud, and the platform runs the code, manages the webhook, and provides Bot API access, a database, and an HTTP client.
Can I use Python?
No, the official runtime is documented for plain JavaScript modules. You can keep Python logic in an external API and call it through fetchor rewrite a compact event-handling layer in JavaScript.
Can I install npm packages?
No. The runtime allows only the platform SDK and your own modules in schema, lib/ and handlers/. Having a package.json is needed for the local CLI, but it does not turn the cloud runtime into standard Node.js.
Do I need my own webhook URL?
No. The platform creates and synchronizes the webhook. The tgcloud webhook command shows the URL, pending updates, the latest error, and whether the deployed handlers match allowed_updates .
What database is used?
Each bot gets a separate SQLite-backed database with a Drizzle-like schema DSL and query builder. Data persists between invocations, but foreign keys are disabled.
Can I build an AI bot with streaming?
Yes, external fetch supports streamed reading of text responses, including SSE and token-by-token output. You need to account for the overall 32 MB limit and design message updates through the Bot API separately.
Is Telegram Serverless free?
In the official documentation available as of July 17, 2026, pricing is not specified. So the correct answer is to check the terms in BotFather and the official materials before launch, not to assume the service is free by default.
When is Telegram Serverless not a good fit?
When the project requires Python/Go, npm packages, a filesystem, uploading and downloading raw files, binary HTTP responses, foreign keys, an external database, long-running workers, or confirmed resource guarantees that are not in the documentation.
Bottom line
Telegram Serverless shortens the path from BotFather to a working backend: the update goes straight to a JavaScript handler, state is stored in the built-in database, Bot API and HTTP are available through one SDK, and deployment runs with a single CLI command. For a small event-driven bot, this removes the VPS, containers, manual webhook setup, and separate operations overhead.
The main tradeoff is a closed and intentionally narrow runtime. It should be evaluated not by the promise of "no server," but by the framework event → module → data → action. If the whole workflow fits into it and passes the limitations table, start with one handler, test it with tgcloud run, then deploy the code and apply the schema through a separate migration. If it does not fit, keep the external backend and use Telegram Serverless only for the suitable layer, or do not migrate the project.
Source of facts and commands: official Telegram Serverless documentation, verified on July 17, 2026.