Короткий ответ: для одного экземпляра бота и до 1000 пользователей SQLite или postgres для Telegram-бота — вопрос, который решается в пользу SQLite почти всегда. PostgreSQL нужен, когда бот растет до нескольких воркеров, требует конкурентной записи или просто едет в серьезный прод с командой на борту. Ниже разберем, где именно проходит граница и как не тащить лишнюю инфраструктуру туда, где она не нужна.
SQLite: встроенная библиотека, ноль настройки, файл на диске. Хватает для MVP и ботов с одним инстансом. PostgreSQL: клиент-серверная архитектура, пулы соединений, параллельная запись. Нужен при масштабировании. В статье: сравнение архитектур, разбор проблемы SQLite на Railway, таблица триггеров перехода и готовая схема с миграциями через Alembic.
Какую субд выбрать для Telegram-бота на старте?
SQLite подходит для 90% ботов на старте: один процесс, до тысячи активных пользователей, локальная разработка. PostgreSQL включаем, когда появляется больше одного воркера или реальная нагрузка на запись.
SQLite - это библиотека, встроенная в Python, а не отдельный сервер. Один файл на диске хранит всю базу, подключение занимает одну строку кода. Для Telegram-бота, который только запускается и проверяет гипотезу, это экономит часы на настройке инфраструктуры и позволяет сфокусироваться на логике бота.
Разработчик Go database performance протестировал SQLite и PostgreSQL на реальных CRUD-сценариях: добавление, обновление, удаление, имитация корзины заказов. Итог теста однозначный: сравнение напрямую некорректно, потому что архитектуры решают разные задачи. SQLite превращает само приложение в движок базы данных, PostgreSQL всегда добавляет сетевой round-trip.
Именно поэтому большинство гайдов сходятся в одном правиле: SQLite локально и на старте, PostgreSQL в проде при первых признаках роста. Ниже разберем, откуда эти признаки берутся и как их отследить до того, как база данных бота начнет тормозить или терять записи.

Чем SQLite принципиально отличается от PostgreSQL?
SQLite - однофайловая библиотека без сети, поддерживает много читателей и только одного писателя одновременно. PostgreSQL - клиент-серверная система с пулом соединений и полноценным параллелизмом на запись.
Ключевая разница не в скорости, а в архитектуре. PostgreSQL - отдельный процесс, к которому бот подключается по сети (даже если сервер стоит рядом на той же машине). Каждый такой запрос - это сетевая операция, а сетевые операции всегда медленнее и дороже прямого обращения к файлу.
SQLite работает наоборот: библиотека читает и пишет прямо в файл на диске, без посредника. Поэтому для одного процесса SQLite часто быстрее на простых операциях. Но у этой простоты есть цена — SQLite допускает неограниченное число одновременных читателей и только одного писателя за раз. Если у бота два воркера пытаются писать одновременно, второй будет ждать блокировку.
| Критерий | SQLite | PostgreSQL |
|---|---|---|
| Архитектура | Встроенная библиотека, файл | Клиент-сервер по сети |
| Параллельная запись | Один писатель одновременно | Полноценный параллелизм |
| Установка | Не требуется, входит в Python | Отдельный сервис или Railway-аддон |
| Подходит для | 1 инстанс бота, MVP, до ~1000 юзеров | Несколько воркеров, рост нагрузки |
| Миграции схемы | Ограничены (нет полного ALTER TABLE) | Полная поддержка через Alembic/Drizzle |
| Стоимость на старте | Бесплатно, без сервиса | Бесплатный тир на Railway с лимитами |
Источник данных теста: сравнение производительности SQLite и PostgreSQL от разработчиков самой SQLite - там же официальная позиция авторов о том, для каких сценариев она задумана.

Почему SQLite на Railway теряет данные бота?
Railway по умолчанию использует ephemeral storage: контейнер пересоздается при каждом деплое, и файл SQLite стирается вместе с ним. Решение - подключить постоянный Volume к сервису.
Вот тут возникает самая частая боль вайбкодеров, которые выкатывают Telegram-бота на Railway. Бот две недели собирал пользователей, а после безобидного редеплоя база пустая. Причина не в баге бота, а в том, как устроено хранилище по умолчанию.
Railway пересоздает контейнер при каждом новом деплое. Все, что лежало в файловой системе контейнера, включая файл users.db, исчезает вместе со старым контейнером. По документации Railway, для сохранения данных между деплоями нужно явно подключить Volume - постоянное блочное хранилище, которое монтируется как директория и переживает пересоздание сервиса.

Практическое правило простое: если оставляешь SQLite в проде на Railway, обязательно цепляй Volume к сервису бота и храни файл базы внутри примонтированной директории, а не в стандартном пути приложения. Без этого шага SQLite в проде - мина замедленного действия, а не полноценное решение.
Максим: «Веб-версия GoBanana была собрана за 3 часа после выхода модели. Суммарно 6-8 часов на продукт, который принес 12 миллионов рублей. Не усложняли инфраструктуру там, где она не нужна была на старте.»

Когда пора переходить на PostgreSQL?
Переходить стоит при появлении второго воркера, росте базы выше несколько тысяч записей с активной записью или при необходимости бэкапов и мониторинга без ручной возни.
Граница между SQLite и postgres для Telegram-бота проходит не по количеству строк в таблице, а по паттерну нагрузки. SQLite прекрасно живет с базой в несколько гигабайт, если пишет туда один процесс. Проблема начинается там, где появляется конкуренция за запись.
| Триггер перехода | Почему это критично для SQLite |
|---|---|
| Больше одного воркера/инстанса бота | Один писатель одновременно - второй ждет блокировку |
| Вебхуки + polling одновременно | Два источника записи в один файл |
| Нужны бэкапы по расписанию | В Postgres это штатная функция, в SQLite - вручную |
| Растущая команда разработчиков | Postgres проще подключить нескольким людям параллельно |
| Аналитика и сложные JOIN на больших таблицах | Postgres оптимизирован под конкурентное чтение и запись |
По результатам теста производительности, обновления (UPDATE) - одна из самых ресурсоемких операций в любой базе, потому что требуют поиска записи по ID и изменения значения. На growth-стадии бота, где статусы подписок и балансы пользователей обновляются постоянно, это первый сигнал присмотреться к PostgreSQL.

Как подключить PostgreSQL на Railway за 5 минут?
В Railway PostgreSQL добавляется как отдельный сервис в проекте одним кликом, а строка подключения автоматически прокидывается в переменные окружения бота.
Шаг 1. В проекте Railway нажми "New" и выбери шаблон PostgreSQL. Сервис поднимется сам, без ручной настройки сервера.
Шаг 2. Скопируй переменную DATABASE_URL из настроек нового сервиса Postgres или подключи её как reference-переменную к сервису бота - тогда она обновится автоматически, если Railway перевыпустит credentials.
Шаг 3. В коде бота замени строку подключения SQLite на DATABASE_URL из окружения. Для aiogram или python-telegram-bot это обычно одна строка в конфиге SQLAlchemy engine.
Шаг 4. Прогони первую миграцию (раздел ниже) на новой базе перед тем, как переключать трафик.
Официальная документация по хранилищам Railway - docs.railway.com/data-storage, там же описаны лимиты бесплатного тира и правила биллинга по объему.

Alembic или Drizzle: как вести миграции схемы?
Alembic - стандарт миграций для Python-проектов на SQLAlchemy. Drizzle - аналог для Node.js/TypeScript-ботов. Оба генерируют версионированные файлы миграций и умеют откатывать изменения.
Для Python-бота на aiogram или python-telegram-bot связка SQLAlchemy + Alembic - фактический стандарт. Alembic хранит историю изменений схемы как последовательность файлов, каждый со своим revision ID, и применяет их по порядку через команду alembic upgrade head.
Отдельный нюанс: SQLite исторически не поддерживает полноценный ALTER TABLE. Alembic решает это через batch_alter_table - пересоздает таблицу с новой структурой под капотом, так что для разработчика синтаксис миграции остается одинаковым что для SQLite, что для PostgreSQL.
Для ботов на Node.js и TypeScript аналогичную роль играет Drizzle ORM - более легкий инструмент с похожей философией версионированных миграций, но заточенный под TS-типизацию с самого начала.
Готовая схема для Telegram-бота: пользователи и подписки
Ниже готовый промпт для AI-инструмента, который сгенерирует схему сразу под SQLite (локально) и PostgreSQL (прод) с миграциями Alembic.
Разница между схемами минимальна, но принципиальна: в PostgreSQL используем UUID вместо INTEGER для ID (проще шардировать и мержить данные в будущем) и TIMESTAMPTZ вместо DATETIME (хранит таймзону, критично, если пользователи бота из разных часовых поясов).
Промпт для Cursor, Windsurf или Claude Code:
«Создай схему для Telegram-бота с пользователями и подписками. Для SQLite (локально): CREATE TABLE с INTEGER PRIMARY KEY и DATETIME. Для PostgreSQL (прод): та же схема, но с UUID вместо INTEGER и TIMESTAMPTZ вместо DATETIME. Покажи alembic-команды для первой миграции (alembic revision --autogenerate,alembic upgrade head) и как откатить (alembic downgrade -1), если что-то пошло не так.»
Такой промпт удобно прогнать через Claude Code или Cursor прямо во время разработки бота - инструмент сгенерирует обе схемы и файл миграции за один запрос, останется только проверить autogenerate руками перед upgrade head.
Если деплой и инфраструктура пока пугают, посмотри каталог агентов для devops-задач на VibeCoderz - там разбор, какой AI-агент под какую часть настройки сервера закрывает.

Часто задаваемые вопросы
Можно ли использовать SQLite в проде для Telegram-бота?
Да, если бот работает одним инстансом и трафик умеренный. Обязательное условие на Railway - подключить Volume, иначе файл базы сотрется при следующем деплое.
Сколько пользователей выдержит SQLite?
Ориентир - до 1000 активных пользователей с одним воркером без проблем. Дальше зависит от паттерна нагрузки: если это в основном чтение, SQLite тянет и больше.
Что случится, если не подключить Volume на Railway?
Файл SQLite будет жить в ephemeral-хранилище контейнера и обнулится при каждом редеплое или пересоздании сервиса. Это самая частая причина "пропавшей" базы у ботов на Railway.
Нужен ли пул соединений для SQLite?
Нет, SQLite не работает по сети, пулы соединений (connection pool) актуальны только для PostgreSQL, где каждое соединение - отдельный сетевой канал.
Как перенести данные с SQLite на PostgreSQL, если бот уже вырос?
Экспортировать данные через скрипт (Python + SQLAlchemy умеет читать из одной базы и писать в другую), прогнать Alembic-миграции на новой Postgres-базе, затем переключить DATABASE_URL бота.
Drizzle или Prisma для Node.js-бота?
Оба варианта рабочие. Drizzle легче и ближе к чистому SQL, Prisma - более высокоуровневый ORM с собственной DSL для схемы. Для миграций из промпта выше подходит Drizzle.
WAL-режим в SQLite - это обязательно?
Нет, но рекомендуется для прод-использования: Write-Ahead Log ускоряет запись и позволяет читать данные, пока идет запись, вместо стандартного rollback journal.
Глоссарий
- SQLite - встроенная в язык программирования библиотека для работы с базой данных, хранит все в одном файле.
- PostgreSQL - клиент-серверная система управления базами данных с полноценным параллелизмом.
- Volume (Railway) - постоянное блочное хранилище, которое подключается к сервису и переживает редеплои.
- Ephemeral storage - временное хранилище контейнера, стирается при пересоздании сервиса.
- WAL (Write-Ahead Log) - режим записи в SQLite, при котором изменения сначала пишутся в отдельный лог, а не сразу в основной файл базы.
- Alembic - инструмент миграций для SQLAlchemy в Python-проектах.
- Connection pool - пул заранее открытых соединений с базой, чтобы не создавать новое соединение на каждый запрос.
Если не уверены, какая схема нужна именно вашему боту, посмотрите каталог AI-инструментов для разработки на VibeCoderz или запишитесь на консультацию к Максиму - разберем архитектуру конкретно под вашу нагрузку.
Обновлено: июль 2026.