Legan Studio
Все статьи
~ 11 мин чтения

python-telegram-bot vs aiogram vs grammY: сравнение фреймворков

Чем отличаются три самых популярных фреймворка для Telegram-ботов: API, производительность, экосистема и подход к диспетчеризации.

  • Telegram
  • разработка
  • сравнение

Выбор фреймворка для Telegram-бота влияет на скорость разработки, тестируемость и поддержку проекта на годы вперёд. python-telegram-bot, aiogram и grammY — три самых живых проекта на 2026 год. Все три полностью покрывают Bot API, отличия — в архитектуре, типизации, экосистеме плагинов и подходе к роутингу. Ниже — детальное сравнение под реальные задачи: от простого FAQ-бота до сложной воронки с платежами, FSM и интеграцией с Mini App.

Главный вывод заранее: «лучшего» фреймворка не существует. Есть удобный для конкретной команды и под конкретный сценарий. Если у вас Python-бэкенд и команда привыкла к asyncio — берите aiogram. Если уже есть Node-стек и Mini App на Next.js — grammY. Если важна максимальная стабильность API и большое сообщество — PTB. Дальше — детально по каждому, с кодом и таблицами.

Языки, runtime и экосистема

python-telegram-bot (далее PTB) и aiogram живут в Python-экосистеме. Установка через pip, зависимости через requirements.txt или pyproject.toml, типизация — через стандартный typing (PTB) или Pydantic (aiogram). Минимальная версия Python — 3.9 для PTB и 3.10 для aiogram 3.

grammY живёт в JavaScript-экосистеме: Node.js 18+, Deno, Bun. Устанавливается через npm/pnpm/yarn/bun. Типизация на TypeScript — настолько глубокая, что без TS работать с grammY теряет смысл: половина DX упирается в автодополнение типов от Context.

С точки зрения runtime: PTB и aiogram — asyncio поверх CPython. grammY — V8 (Node), JavaScriptCore (Bun) или Deno-runtime. Бенчмарки echo-бота показывают, что Bun обгоняет CPython в 2-3 раза, но в реальных ботах разница нивелируется ожиданием Bot API и БД.

DX и стиль API

Три фреймворка предлагают принципиально разные стили описания хэндлеров.

PTB — императивный: создаёте Application, регистрируете Handler-объекты руками.

from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Привет!")

app = Application.builder().token("TOKEN").build()
app.add_handler(CommandHandler("start", start))
app.run_polling()

aiogram 3 — декораторы и роутеры в стиле FastAPI:

from aiogram import Bot, Dispatcher, Router, F
from aiogram.filters import CommandStart
from aiogram.types import Message, CallbackQuery

router = Router()

@router.message(CommandStart())
async def start(message: Message):
    await message.answer("Привет!")

@router.callback_query(F.data == "ping")
async def ping(call: CallbackQuery):
    await call.answer("pong")

dp = Dispatcher()
dp.include_router(router)

grammY — middleware-pipeline в духе koa/express:

import { Bot, Composer } from "grammy";

const bot = new Bot(process.env.BOT_TOKEN!);
const composer = new Composer();

composer.command("start", (ctx) => ctx.reply("Привет!"));
composer.callbackQuery("ping", (ctx) => ctx.answerCallbackQuery("pong"));

bot.use(composer);
bot.start();

Декораторы aiogram читаются проще для тех, кто привык к FastAPI/Flask. Middleware-стиль grammY — гибче: легко вставлять промежуточные слои в любой точке. PTB занимает середину: явная регистрация даёт контроль, но многословна.

Роутинг и композиция

В PTB всё крутится вокруг Application и Handler. Группы хэндлеров (group=N) — единственный способ упорядочить обработку. Вложенных роутеров нет; разделение по файлам делается руками — собираете список хэндлеров и регистрируете через add_handler.

aiogram 3 ввёл Router — иерархическая композиция в духе FastAPI:

from aiogram import Router

admin_router = Router()
user_router = Router()

@admin_router.message(F.from_user.id.in_({111, 222}))
async def admin_only(message: Message):
    await message.answer("Привет, админ")

@user_router.message()
async def echo(message: Message):
    await message.answer(message.text)

main_router = Router()
main_router.include_router(admin_router)
main_router.include_router(user_router)

grammY использует Composer — каждый Composer это middleware-стек, и bot сам по себе тоже Composer. Композиция тривиальна:

import { Composer } from "grammy";

const admin = new Composer();
admin.use((ctx, next) => {
  if (ctx.from?.id !== 111) return;
  return next();
});
admin.command("ban", (ctx) => ctx.reply("забанено"));

const user = new Composer();
user.on("message:text", (ctx) => ctx.reply(ctx.message.text));

bot.use(admin);
bot.use(user);

Для крупных ботов (50+ хэндлеров) роутинг aiogram и Composer-цепочки grammY дают ощутимо более чистый код, чем плоская регистрация PTB.

FSM и сценарии

FSM (finite state machine) — обязательный инструмент для воронок: «введи имя → введи телефон → выбери услугу → подтверди». Все три фреймворка поддерживают FSM, но по-разному.

PTB предлагает ConversationHandler — мощный, но многословный:

from telegram.ext import ConversationHandler, MessageHandler, filters

NAME, PHONE = range(2)

async def ask_name(update, context):
    await update.message.reply_text("Имя?")
    return NAME

async def got_name(update, context):
    context.user_data["name"] = update.message.text
    await update.message.reply_text("Телефон?")
    return PHONE

async def got_phone(update, context):
    context.user_data["phone"] = update.message.text
    await update.message.reply_text(f"Спасибо, {context.user_data['name']}")
    return ConversationHandler.END

conv = ConversationHandler(
    entry_points=[CommandHandler("order", ask_name)],
    states={
        NAME: [MessageHandler(filters.TEXT, got_name)],
        PHONE: [MessageHandler(filters.TEXT, got_phone)],
    },
    fallbacks=[],
)
app.add_handler(conv)

aiogram 3 — StatesGroup и FSMContext:

from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.context import FSMContext

class Order(StatesGroup):
    name = State()
    phone = State()

@router.message(CommandStart())
async def start_order(message: Message, state: FSMContext):
    await state.set_state(Order.name)
    await message.answer("Имя?")

@router.message(Order.name)
async def got_name(message: Message, state: FSMContext):
    await state.update_data(name=message.text)
    await state.set_state(Order.phone)
    await message.answer("Телефон?")

@router.message(Order.phone)
async def got_phone(message: Message, state: FSMContext):
    data = await state.update_data(phone=message.text)
    await state.clear()
    await message.answer(f"Спасибо, {data['name']}")

grammY — плагин @grammyjs/conversations. Это лучший FSM в классе, потому что код выглядит синхронным:

import { conversations, createConversation } from "@grammyjs/conversations";

async function order(conversation, ctx) {
  await ctx.reply("Имя?");
  const { message: nameMsg } = await conversation.waitFor("message:text");
  await ctx.reply("Телефон?");
  const { message: phoneMsg } = await conversation.waitFor("message:text");
  await ctx.reply(`Спасибо, ${nameMsg.text}`);
}

bot.use(conversations());
bot.use(createConversation(order));
bot.command("order", (ctx) => ctx.conversation.enter("order"));

Состояние сохраняется автоматически: библиотека делает await непрозрачным — диалог приостанавливается до следующего обновления, потом возобновляется. Для длинных ветвящихся воронок это разница между «писать FSM-схему» и «писать обычный код».

Middleware и фильтры

PTB: middleware как такового нет. Есть TypeHandler, который можно поставить в группу с меньшим приоритетом, и есть error_handler. Throttling, логирование, авторизацию — пишете руками.

aiogram 3: middleware на уровне диспетчера, роутера и observer-ов:

from aiogram import BaseMiddleware
from typing import Any, Callable, Awaitable, Dict

class LoggingMiddleware(BaseMiddleware):
    async def __call__(self, handler, event, data):
        print(f"-> {event.text if hasattr(event, 'text') else event}")
        return await handler(event, data)

router.message.middleware(LoggingMiddleware())

Фильтры aiogram — через магический F или классы:

@router.message(F.text.regexp(r"^\d{10,11}$"))
async def phone_handler(message: Message):
    await message.answer("Похоже на телефон")

grammY: middleware — это вся архитектура. Любой bot.use(...) — middleware. Throttling и flood-protection — плагины:

import { run } from "@grammyjs/runner";
import { apiThrottler } from "@grammyjs/transformer-throttler";

bot.api.config.use(apiThrottler());
bot.use(async (ctx, next) => {
  console.time("handler");
  await next();
  console.timeEnd("handler");
});

run(bot);

По удобству: aiogram и grammY на голову выше PTB. У grammY ещё и встроенный runner для concurrent webhook processing.

Платежи, файлы, inline mode, scheduler

ВозможностьPTBaiogram 3grammY
Telegram Stars / XTRдадада
Pre-checkoutдадада
File upload (InputFile)дадада
Inline modeдадада
Webhookда (run_webhook)да (aiohttp/fastapi)да (webhookCallback)
Scheduler из коробкиJobQueueнет (apscheduler)нет (плагин или внешнее)
Long pollingдадада (через runner)

JobQueue в PTB — единственный встроенный планировщик. В aiogram и grammY стандарт — внешние библиотеки (apscheduler для Python, node-cron для Node). На практике это не минус: планировщик обычно живёт отдельным сервисом.

Тестирование

Telegram-боты сложно тестировать end-to-end, потому что нужен живой Bot API. Все три фреймворка поощряют unit-тесты на хэндлерах с моком Bot/Context.

aiogram даёт MockedBot через сторонний aiogram-tests:

from aiogram_tests import MockedBot
from aiogram_tests.handler import RequestHandler
from aiogram_tests.types.dataset import MESSAGE

async def test_start():
    requester = RequestHandler(request_handler=start, dp=dp)
    calls = await requester.query(MESSAGE.as_object(text="/start"))
    answer = calls.send_message.fetchone()
    assert answer.text == "Привет!"

grammY поставляет официальный тест-кит — проще:

import { Bot } from "grammy";

const bot = new Bot("dummy");
bot.command("start", (ctx) => ctx.reply("Привет!"));

await bot.handleUpdate({
  update_id: 1,
  message: { /* fake message object */ } as any,
});

PTB тестируется через pytest-asyncio и ручной мок Update/Context. Готовых хелперов меньше.

Документация и сообщество

  • PTB: GitHub stars 25k+, релизы раз в 1-2 месяца, активный список рассылки. Документация — readthedocs, исчерпывающая, с tutorial.
  • aiogram: 5k+ stars, очень активный Telegram-чат на русском, релизы регулярно. Дока — docs.aiogram.dev, на английском, но есть кириллические туториалы в комьюнити.
  • grammY: 5k+ stars, документация — grammy.dev, многоязычная (включая русский раздел), отличные примеры под каждый плагин. Самое аккуратное оформление из трёх.

По числу Stack Overflow ответов лидер — PTB. По активности комьюнити в РФ — aiogram. По качеству официальной документации — grammY.

Стабильность API и breaking changes

PTB славится стабильностью: миграция между мажорными версиями болезненна (особенно 13 → 20 на asyncio), но внутри мажора API почти не меняется. Релизы 21.x обратно совместимы.

aiogram пережил болезненный 2 → 3: переписан с нуля, поменялся синтаксис, FSM, фильтры. Сейчас 3.x стабилен, но проектов на aiogram 2 ещё много. Внутри 3.x — минимальные изменения.

grammY развивается быстрее: 1.x → 2.x не было, всё в рамках мажора. Плагины обновляются часто, но breaking changes сопровождаются гайдами миграции и codemod-ами.

Производительность

Синтетический echo-бот, одно ядро, без БД, webhook режим:

ФреймворкRPS (echo)Latency p99
PTB 21 + uvicorn3000-50008 мс
aiogram 3 + uvloop4000-60006 мс
grammY + Node 206000-90004 мс
grammY + Bun 1.x8000-120003 мс

В реальной жизни узкое место — БД, внешние API, очереди. Любой из трёх легко тянет 100-500 RPS, чего хватает 99% проектов. Считать «фреймворк лимитирует» можно только при 5k+ RPS на инстанс.

Зрелость в продакшене и типичные грабли

PTB:

  • JobQueue живёт в одном процессе — при горизонтальном масштабировании задачи не перенесутся, нужен внешний планировщик.
  • context.user_data хранится в памяти по умолчанию — нужен PicklePersistence или внешнее хранилище.

aiogram:

  • FSM-storage по умолчанию MemoryStorage — теряется при рестарте; в проде нужен Redis или Mongo.
  • Middleware регистрируется на конкретный observer (message, callback_query) — легко забыть про один.
  • Bot(session=...) нужно явно закрывать в shutdown, иначе утечка соединений.

grammY:

  • Без @grammyjs/runner обработка webhook-ов последовательная — на крупном боте без runner деградация.
  • Сессии (session() middleware) по умолчанию in-memory — те же грабли, что у aiogram.
  • Conversations требуют чистых функций (без побочных эффектов вне await ctx.*), иначе при возобновлении логика ломается.

Когда что выбирать

СценарийРекомендация
Простой бот, команда уже знает PTBPTB
Воронка с FSM, команда на Pythonaiogram 3
Бот + Mini App в одной кодовой базеgrammY (TS на фронте и беке)
Высокая нагрузка (5k+ RPS)grammY на Bun
Корпоративный проект, важна стабильностьPTB или aiogram 3
Open-source бот с долгой поддержкойaiogram 3 (большое RU-комьюнити)
Bot API на самом краю (новые фичи в день релиза)grammY

Итого

PTB — стабильность, наследие и встроенный JobQueue. aiogram 3 — лучший Python-DSL, удобная FSM, активное русскоязычное сообщество. grammY — TypeScript, скорость, чистая архитектура и conversations-плагин, переворачивающий FSM. Принципиальной разницы по покрытию Bot API нет; разница — в стиле, типизации, экосистеме плагинов и зрелости документации. Выбирайте под стек команды и сложность сценариев, а не под маркетинг — все три дотащат проект до production.

Частые вопросы

Чем отличается python-telegram-bot от aiogram 3?

PTB — императивный API, хэндлеры регистрируются через application.add_handler, middleware-системы как таковой нет, фильтры — отдельные классы. Сильные стороны: огромное количество примеров и Stack Overflow ответов, стабильное API с минимумом breaking changes между мажорными версиями, встроенный JobQueue — планировщик задач без внешних зависимостей. aiogram 3 — декораторы в стиле FastAPI, роутеры с иерархической композицией, FSM из коробки через StatesGroup и FSMContext, удобные middleware на уровне диспетчера и роутера, фильтры через магический объект F. PTB подходит, когда команда уже знает его и важна стабильность; для нового проекта чаще выбирают aiogram 3.

Почему aiogram 3 популярен у русскоязычных разработчиков?

aiogram — самый популярный фреймворк у русскоязычных разработчиков. Версия 3 переписана с нуля, использует Pydantic для типов, FSM из коробки, роутеры в стиле FastAPI. Декораторы router.message(F.text == /start) — компактно. Filter через магический объект F — выразительно (F.photo, F.text.regexp). FSMContext встроен в любой хэндлер. Хорошая интеграция с Pydantic — все объекты типизированы. Удобные middleware на уровне диспетчера, роутера и observer-ов. Минусы: breaking changes между 2 и 3, меньше готовых решений на английском Stack Overflow, иногда обновления Bot API доезжают чуть позже, чем у grammY. В РФ — стандартный выбор для новых ботов.

Когда выбирать grammY вместо aiogram или PTB?

grammY — молодой фреймворк на TypeScript для Node, Deno, Bun. Подходит, если фронт на TypeScript или хочется одной кодовой базой закрыть и бот, и Mini App, и бэкенд. Сильные стороны: современная типизация — все объекты Telegram строго типизированы, IDE подсказывает каждое поле; плагины (menu, conversations, runner, storage) с понятным API; быстрый рантайм, особенно на Bun (в 2-3 раза быстрее Python); удобный middleware-стиль в духе koa/express; активная многоязычная документация на grammy.dev. Слабые места: TypeScript обязателен, меньше русскоязычных туториалов, некоторые продвинутые сценарии требуют дополнительных плагинов. Лучший выбор для проектов с Mini App и для команд на Node.

Какой фреймворк быстрее в бенчмарках?

Синтетический echo-бот, одно ядро, webhook режим: PTB 21 на uvicorn — 3000-5000 RPS; aiogram 3 на uvloop — 4000-6000 RPS; grammY на Node 20 — 6000-9000 RPS; grammY на Bun — 8000-12000 RPS. В реальной жизни узким местом почти никогда не будет фреймворк. Ботам мешают БД, внешние API, очереди. Любой из трёх легко тянет 100-500 RPS, что достаточно для подавляющего большинства проектов. Выбирать фреймворк по бенчмаркам — преждевременная оптимизация: при росте до 10k RPS у вас будут другие проблемы (БД, очереди), а не фреймворк. Считать фреймворк ограничивающим можно только при 5k+ RPS на инстанс.

Как FSM реализован в каждом из фреймворков?

PTB: ConversationHandler — мощный, но многословный. Хорошо подходит для линейных сценариев, плохо для ветвящихся — при 5+ состояниях код становится тяжёлым. aiogram 3: StatesGroup + FSMContext + middleware-провайдеры состояния (Redis, MongoDB, Memory) — понятно с первого раза, FSM-context доступен в любом хэндлере как параметр. grammY: плагин conversations — лучший в классе, потому что позволяет писать код «как в синхронном стиле»: await conversation.waitFor(message:text), await conversation.ask. Состояние сохраняется автоматически — библиотека приостанавливает выполнение до следующего обновления. Для длинных воронок grammY conversations выигрывает у обоих Python-фреймворков по DX.

Что насчёт middleware и фильтров?

PTB: middleware как такового нет. Throttling, логирование, авторизацию приходится писать руками через TypeHandler в группе с меньшим приоритетом и error_handler. aiogram 3: middleware на уровне диспетчера, роутера и observer-ов; фильтры через магический F или классы (F.text.regexp, F.photo, F.from_user.id.in_). grammY: middleware — основа архитектуры, любой bot.use это middleware; throttling и flood-protection — отдельные плагины (apiThrottler, transformer-throttler); встроенный runner для concurrent webhook processing. По удобству aiogram и grammY на голову выше PTB.

Как выбрать фреймворк под свой Telegram-бот?

Простое правило по стеку команды и задаче. Команда на Python, нужен максимально стабильный фреймворк без сюрпризов и встроенный JobQueue — PTB. Команда на Python, нужен современный API, FSM и активное RU-сообщество — aiogram 3. Команда на TypeScript, Node, Deno или Bun, ставка на Mini App или единая кодовая база — grammY. По нагрузке: до 1k RPS — любой; 5k+ RPS — grammY на Bun. Если бот единичный и простой, можно вообще обойтись HTTP-сервером и ручными вызовами Bot API. Но как только появляются 10+ хэндлеров и FSM, фреймворк экономит десятки часов разработки и сопровождения.