⏱️ Lectura: 11 min

Telegram just turned its own infrastructure into hosting for your bot: with Telegram Serverless, the code that responds to a message or a button press runs directly on Telegram’s servers, without you having to spin up a VPS, a container, or a third-party cloud function.

📑 En este artículo
  1. TL;DR
  2. What Telegram Serverless is and why it matters
  3. How the three-layer mental model works
  4. Practical examples: from hello world to a real case
  5. How to get started step by step
  6. Real-world use cases
  7. Common mistakes and best practices
  8. Comparison with alternatives
  9. Going deeper: what happens under the hood
  10. Frequently Asked Questions
    1. Does Telegram Serverless fully replace a VPS?
    2. What happens to the data if my bot gets a sudden traffic spike?
    3. Can I use external npm libraries inside the modules?
    4. Do I need a Telegram Business account or a special developer account?
    5. How do I test a handler before deploying it to production?
    6. Can schema.js migrations be rolled back?
  11. References

If you have ever stood up a server just so your bot could answer /start, this platform removes that step entirely: you write JavaScript modules, deploy them with a single command, and Telegram runs them alongside its own API and an included database.

TL;DR

  • You’ll understand what Telegram Serverless is and how it replaces a VPS or cloud function for bots.
  • You’ll learn the three-layer model: local folder, the Telegram cloud, and the tgcloud CLI.
  • You’ll be able to write handlers/message.js that respond to updates using the API and a SQLite database.
  • You’ll know how to define tables in schema.js using the SDK’s table() and integer() DSL.
  • You’ll deploy with npx tgcloud push and migrate the schema with npx tgcloud migrate.
  • You’ll tell when Serverless is a better fit than a traditional VPS or an external cloud function.
  • You’ll spot the common mistakes when migrating an existing bot to this model.

What Telegram Serverless is and why it matters

Telegram Serverless is a backend runtime built into the platform: it lets you write the code that processes your bot’s updates (messages, buttons, inline queries) as plain JavaScript modules, without managing any server of your own. Telegram runs it in an isolated V8 sandbox that executes close to the Bot API, which reduces the latency between receiving an update and responding.

The offering solves a problem anyone who has built a bot knows well: for /start to work 24/7, you needed a process that was always on, reachable from the internet, and patched. With Serverless that process doesn’t exist: your code runs on demand and scales automatically with your bot’s traffic.

The platform is not a template for a single kind of app. According to the official documentation, it serves conversational bots with per-user state, the backend of a Mini App, games with leaderboards, and automations that call external HTTP APIs and post the results into a chat.

📌 Note: before writing a single line of code, you have to enable the feature. In @BotFather: open your bot, go to Serverless, and turn it on. That unlocks the CLI token, the handlers, the library, and the database.

How the three-layer mental model works

You work in three places that map one to one. Your local folder holds the versioned code; the Telegram cloud holds the deployed copy of those modules plus your bot’s database; and the tgcloud CLI is the bridge that shows you the differences between the two and syncs them.

Developer writing a bot's code on their laptop
The code lives in your local folder, versioned like any other project. Foto de Deeksha Pahariya en Unsplash

You never SSH anywhere. You edit files locally, run npx tgcloud push, and the platform handles the rest. Your bot’s traffic is served by the deployed copy; the database persists between invocations even though each handler run is ephemeral.

A project has only three kinds of code: handlers/ with one file per update type, lib/ with shared code you import from any handler, and schema.js with your database tables.

flowchart TD
    A["Carpeta local: handlers, lib, schema.js"] --> B["npx tgcloud push"]
    B --> C["La nube de Telegram: modulos + base de datos"]
    C --> D["Bot responde updates en produccion"]

When an update arrives (a message, a pressed button, an inline query), Telegram routes it to the corresponding handler (handlers/message.js, handlers/callback_query.js, etc.) and calls its default export. That function talks to the Bot API and the database through the SDK, then returns. An update with no handler to serve it is simply ignored, so you add only the handlers you need.

Practical examples: from hello world to a real case

The simplest possible handler receives a message and replies. It doesn’t touch the database and imports nothing beyond the API SDK:

import { api } from 'sdk';

export default async function (message) {
  await api.sendMessage({
    chat_id: message.chat.id,
    text: `Recibi tu mensaje: ${message.text ?? '(sin texto)'}`,
  });
}

This file goes in handlers/message.js. Deployed with npx tgcloud push, it’s already a live bot that echoes every message: there’s no database and no state, so there’s no need to run any migration.

The next example gets closer to a real case: a support bot that counts how many tickets each chat has opened and remembers the last subject. First we define the table in schema.js:

import { table, integer, text } from 'sdk/db';

export const tickets = table('tickets', {
  chatId: integer('chat_id').primaryKey(),
  abiertos: integer('abiertos').notNull().default(0),
  ultimoAsunto: text('ultimo_asunto'),
});

And then the handler that inserts or updates that row on every message, using onConflictDoUpdate to increment the counter atomically:

import { api, db } from 'sdk';
import { tickets } from 'schema';
import { sql } from 'sdk/db';

export default async function (message) {
  const chatId = message.chat.id;
  const asunto = message.text ?? 'Sin asunto';

  const [fila] = await db.insert(tickets)
    .values({ chatId, abiertos: 1, ultimoAsunto: asunto })
    .onConflictDoUpdate({
      target: tickets.chatId,
      set: { abiertos: sql`${tickets.abiertos} + 1`, ultimoAsunto: asunto },
    })
    .returning()
    .run();

  await api.sendMessage({
    chat_id: chatId,
    text: `Ticket #${fila.abiertos} registrado para este chat. Asunto: ${fila.ultimoAsunto}`,
  });
}

With this you already have a bot with persistent per-chat state, without ever touching a server. The expected result: each new message returns a ticket number that increments and stores the last subject received.

sequenceDiagram
    participant U as Usuario
    participant T as Telegram
    participant H as Handler en V8
    participant D as Base de datos
    U->>T: envia mensaje
    T->>H: entrega el update
    H->>D: inserta o actualiza fila
    D-->>H: devuelve fila actualizada
    H-->>T: llama a api.sendMessage
    T-->>U: muestra la respuesta

How to get started step by step

You need Node.js 18 or higher and a bot already registered with @BotFather. First install Node according to your operating system.

Windows:

winget install OpenJS.NodeJS.LTS

macOS:

brew install node

Linux (Debian/Ubuntu):

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

With Node installed, the rest of the steps are identical across all three platforms. First enable Serverless in @BotFather (Bot → Serverless → enable) and then create the project:

npm create @tgcloud/bot soporte_bot
cd soporte_bot

The command scaffolds a folder ready to edit, with an example handler in handlers/message.js and a docs/tgcloud-sdk.md file with the SDK reference. Pass . as an argument if you want to scaffold in the current folder.

Write your schema.js and your handlers as in the examples above, and then deploy:

npx tgcloud push
npx tgcloud migrate
npx tgcloud status

push uploads your modules, migrate applies pending schema changes against the cloud database, and status shows you which version is running in production and whether there are undeployed differences. Use run to test a specific handler before deploying.

Real-world use cases

An AI conversational bot that needs to remember each user’s context between messages fits naturally: state lives in the table, not in the memory of a process that can restart. A Mini App backend can use the same handlers to serve dynamic data to the frontend embedded in Telegram without exposing a separate public endpoint.

For games and tools, the included database works for leaderboards and quizzes without hiring an external engine. And for automations and integrations, the outbound HTTP available in each module lets you call third-party APIs and post the result to a channel, for example a bot that checks a feed at intervals and posts alerts.

Common mistakes and best practices

The most frequent mistake when migrating an existing bot is forgetting that there is no persistent filesystem: any state your bot needs to remember between invocations has to live in the schema.js table, not in a global variable or a temporary file.

⚠️ Watch out: if you run tgcloud push without having run tgcloud migrate after adding a new table, the handler will fail when it tries to read from or write to a table that doesn’t yet exist in the deployed database.

Another typical slip is assuming that an update without a handler triggers some error: it’s actually ignored silently, so if your bot doesn’t respond to a type of update, check first whether the corresponding file is missing from handlers/ before suspecting the internal logic.

Finally, treat migrations as reviewed code, not an automatic step: every schema change is recorded and versioned alongside the rest of the project, so a git diff over schema.js should be as readable as any other code change.

Comparison with alternatives

Option When to use it Advantage Limitation
Telegram Serverless Bots and Mini Apps with no need for your own infrastructure Zero servers, database and API included, atomic deploy Coupled to Telegram, not suitable for logic outside the bot’s ecosystem
Your own VPS Bots that already integrate other in-house services or require full control of the environment Absolute control of the runtime and the operating system You have to keep it running, patch it, and scale it manually
Cloud Function (Lambda, Cloud Run) Backends that, beyond Telegram, also serve other clients or channels Portable across providers, integrates with the rest of a cloud stack You have to wire up the Bot API, the database, and the credentials yourself
Hosting panel (cPanel/Heroku style) Quick prototypes with a graphical management interface Visual configuration, little infrastructure knowledge required Less fine-grained control, dependence on the panel provider

Going deeper: what happens under the hood

Each handler invocation runs in a lightweight V8 isolate, the same isolation mechanism used by runtimes like Cloudflare Workers or Deno Deploy: a separate execution context per invocation, without the cost of starting a full operating-system process. By running physically close to the Bot API infrastructure, calls to api.* and to the database have fewer network hops than a handler hosted on another cloud provider.

💭 Key point: the deploy is atomic: tgcloud push replaces all modules at once, not file by file, so there’s no window where the bot runs with a mix of old and new code.

The included database is backed by SQLite, which explains why the SDK exposes a table DSL (table(), integer(), text()) instead of asking you for a connection string: there’s no separate database server to configure, just the file managed by the platform.

flowchart LR
    A["Editar schema.js y handlers/"] --> B["npx tgcloud push"]
    B --> C["npx tgcloud migrate"]
    C --> D["npx tgcloud status"]
    D --> E["Bot en produccion"]

To confirm a deploy went live, npx tgcloud status shows the deployed version and whether your local copy differs from the cloud; no external panel is needed to verify it.

📖 Summary on Telegram: View summary

Your next step: clone the example project with npm create @tgcloud/bot, add your own table in schema.js, and deploy it with tgcloud push followed by tgcloud migrate to see the full cycle in a real bot.

Frequently Asked Questions

Does Telegram Serverless fully replace a VPS?

For the bot logic itself, yes. If your backend also serves other clients outside Telegram, you’ll still need that separate infrastructure.

What happens to the data if my bot gets a sudden traffic spike?

Execution scales automatically because each invocation runs in its own isolate; there’s no single process that gets overwhelmed.

Can I use external npm libraries inside the modules?

The project is structured as standard JavaScript code in lib/, though external dependencies are subject to what the platform’s V8 sandbox supports.

Do I need a Telegram Business account or a special developer account?

No, a bot registered with @BotFather with the Serverless option enabled from the bot’s panel is enough.

How do I test a handler before deploying it to production?

The CLI includes the run command to execute a specific handler locally before uploading it with push.

Can schema.js migrations be rolled back?

They’re managed as reviewed changes within the normal tgcloud migrate flow, versioned alongside the rest of the project just like any other code file.

References

  • Telegram Serverless: official documentation with the full reference for the SDK, the CLI, and the project model.
  • Telegram Bot API: reference for the methods available on the SDK’s api object.
  • SQLite: the database engine that backs the storage included in each project.
  • Node.js: runtime required at version 18 or higher to use the tgcloud CLI.

📱 Enjoy this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day. @programacion

Imagen destacada: Foto de Hazel Z en Unsplash


Andrés Morales

Developer and AI researcher. Writes about language models, frameworks, developer tooling, and open source releases. Covers ML papers, the tech startup ecosystem, and programming trends.

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.