При старте нового веб-проекта вопрос базы данных часто звучит слишком просто:
Что выбрать — PostgreSQL или SQLite?
После этого обычно появляются два противоположных мнения.
Первое:
SQLite подходит только для тестов и маленьких приложений. Для настоящего production нужен PostgreSQL.
Второе:
Зачем поднимать отдельный сервер БД, если SQLite прекрасно хранит всё в одном файле?
Оба утверждения слишком упрощают картину.
SQLite — не «облегчённый PostgreSQL».
PostgreSQL — не «SQLite для больших проектов».
У этих систем разная архитектурная идея.
Официальная документация SQLite прямо отмечает, что SQLite не совсем корректно рассматривать как прямого конкурента PostgreSQL и другим клиент-серверным СУБД. PostgreSQL ориентирован на централизованное многопользовательское хранилище, concurrency и управление общими данными. SQLite — на локальное встроенное хранилище с минимальной эксплуатационной сложностью.
Поэтому правильный вопрос звучит иначе:
какая из этих архитектур лучше соответствует конкретному продукту?
Разберём это на примерах.
Главное различие видно ещё до первого SQL-запроса
Представим SQLite.
Приложение открывает файл:
app.dbи работает с ним напрямую:
Application
↓
SQLite library
↓
app.dbОтдельного процесса базы данных нет.
SQLite встроен непосредственно в приложение и читает или записывает database file на диске. Именно поэтому его называют serverless в классическом смысле: отдельный database server устанавливать и администрировать не требуется.
PostgreSQL устроен иначе:
Application
↓
TCP / Unix socket
↓
PostgreSQL Server
↓
Database filesПриложение является клиентом.
PostgreSQL — отдельным серверным процессом, который принимает соединения, выполняет запросы, управляет транзакциями и координирует параллельную работу клиентов. В актуальной документации PostgreSQL описывается именно клиент-серверная модель соединений.
Это различие определяет почти всё остальное.
Почему SQLite настолько удобен
Допустим, мы разрабатываем внутренний инструмент.
Нужно хранить:
settings
projects
notes
historyС SQLite не требуется:
устанавливать PostgreSQL;
создавать database user;
открывать порт;
настраивать service;
следить за connection pool.Приложению достаточно иметь доступ к файлу:
data/app.sqliteДля небольшого приложения это очень сильное преимущество.
Deployment может выглядеть так:
Application
+
app.sqliteИ всё.
Базу можно буквально перенести одним файлом
Это особенно удобно для:
desktop-приложений;
локальных утилит;
мобильных приложений;
offline-first клиентов;
внутренних инструментов;
небольших односерверных сервисов.Формат SQLite специально рассчитан на такое локальное использование. Официальная документация приводит в качестве типовых сценариев desktop-приложения, embedded-системы, локальные кэши и даже серверные приложения с подходящей моделью нагрузки.
Поэтому фраза «SQLite не годится для production» неверна
SQLite вполне способен работать в production.
Более того, сами разработчики SQLite указывают, что он подходит для многих сайтов с низкой и средней нагрузкой, если характер работы с базой соответствует его архитектуре.
Но здесь есть важная оговорка.
Количество HTTP-запросов само по себе почти ничего не говорит о пригодности базы.
Намного важнее:
сколько одновременных записей;
как долго длятся транзакции;
сколько процессов работают с БД;
нужно ли несколько серверов приложения;
где физически находится database file.Именно здесь PostgreSQL и SQLite начинают заметно расходиться.
Представим обычный небольшой сайт
Есть:
статьи;
формы обратной связи;
несколько администраторов;
пара тысяч посетителей в день.Большинство запросов:
SELECTРедкие операции:
INSERT contact_request
UPDATE articleОдин backend.
Один VPS.
Для такого проекта SQLite может работать превосходно.
Он прост.
Быстр.
Нет отдельного сетевого round trip между приложением и БД.
Практически отсутствует административная нагрузка.
Переходить на PostgreSQL исключительно ради того, чтобы проект выглядел «серьёзнее», необязательно.
А теперь представим CRM
Одновременно работают:
50 менеджеров;
администраторы;
background worker;
интеграция с 1С;
webhook;
очередь задач.В одну секунду происходят:
создание сделки;
обновление статуса;
добавление сообщения;
загрузка документа;
фиксация webhook;
создание notification job.Здесь характер нагрузки уже другой.
Система активно пишет данные из нескольких процессов.
Именно в такой ситуации архитектура PostgreSQL начинает давать заметное преимущество.
Главный вопрос — конкурентная запись
SQLite отлично поддерживает параллельное чтение.
Но с параллельной записью есть фундаментальное ограничение.
Даже в WAL-режиме, который значительно улучшает concurrency, SQLite допускает одновременную работу читателей с писателем, но в каждый момент времени существует только один writer на database file.
Упрощённо:
Reader 1 ──────┐
Reader 2 ──────┼── SQLite
Reader 3 ──────┘
Writer 1 ───────── WRITE
Writer 2 ───────── WAITДля многих приложений это вообще не проблема.
Write transaction занимает миллисекунды.
Следующий writer быстро получает очередь.
Но если write-heavy нагрузка растёт, эта особенность начинает становиться архитектурным ограничением.
WAL сильно улучшает SQLite, но не превращает его в PostgreSQL
В Write-Ahead Logging режиме схема примерно такая:
Reader ──────→ database snapshot
Writer ──────→ WALЧитатели могут продолжать работать, пока происходит запись.
Это очень полезно.
Но WAL остаётся одним журналом, поэтому одновременно пишет всё равно один writer. Кроме того, SQLite WAL рассчитан на процессы на одной машине и не предназначен для обычного использования через сетевую файловую систему.
Поэтому сценарий:
Server A
\
shared SQLite file
/
Server Bобычно является плохой идеей.
PostgreSQL изначально проектировался под многопользовательскую работу
PostgreSQL использует MVCC — Multiversion Concurrency Control.
В упрощённом виде это означает, что транзакции работают со своими согласованными версиями данных.
Обычные чтения не должны блокировать обычные записи, а записи — чтения. PostgreSQL специально оптимизирует конкурентную работу множества сессий в одной общей БД.
Условно:
API #1 ── INSERT ──┐
API #2 ── UPDATE ──┤
Worker ── UPDATE ──┼→ PostgreSQL
Admin ── SELECT ──┤
API #3 ── SELECT ──┘Это именно тот класс задач, ради которого существует клиент-серверная СУБД.
Это не означает, что PostgreSQL никогда ничего не блокирует
Такое утверждение тоже было бы неверным.
В PostgreSQL существуют:
row locks;
table locks;
deadlocks;
serialization conflicts.Два процесса, изменяющие одну строку, вполне могут конфликтовать.
Но база предоставляет значительно более развитую систему управления параллельными транзакциями.
Это особенно важно для:
платежей;
остатков;
заказов;
очередей;
ролей;
финансовых операций;
state machine.Практический пример: последний товар на складе
Есть:
stock = 1Два клиента одновременно покупают товар.
Нужно получить:
клиент A → success
клиент B → out of stockа не:
stock = -1В PostgreSQL можно использовать транзакцию и блокировку строки:
BEGIN;
SELECT stock
FROM products
WHERE id = 184
FOR UPDATE;
UPDATE products
SET stock = stock - 1
WHERE id = 184;
COMMIT;В реальном проекте добавятся проверки, но смысл понятен:
база участвует в конкурентном бизнес-процессе.
SQLite тоже имеет транзакции
Важно не создавать ложного впечатления, что SQLite — просто файл без нормальной БД.
SQLite поддерживает ACID-транзакции.
То есть:
BEGIN
UPDATE
INSERT
COMMITработает совершенно серьёзно.
Для однопользовательских и умеренно конкурентных приложений этого часто более чем достаточно.
Проблема не в отсутствии транзакций.
Проблема появляется тогда, когда количество одновременно конкурирующих writers становится частью нормальной работы продукта.
Ещё одно важное различие — типизация
PostgreSQL — строго типизированная СУБД.
Если мы объявили:
price numeric(12,2)это действительно определённый тип данных.
Если поле:
created_at timestamptzPostgreSQL работает с timestamp.
Если:
id uuidэто настоящий UUID type. PostgreSQL также имеет специализированные типы вроде jsonb с отдельными операторами и индексированием.
SQLite исторически использует более гибкую модель
В SQLite тип относится прежде всего к самому значению, а колонка имеет type affinity.
То есть объявление:
CREATE TABLE example (
value INTEGER
);не означает абсолютно такую же жёсткость, как INTEGER в PostgreSQL.
SQLite способен выполнять автоматические преобразования и хранить значения гибче. Официальная документация называет это dynamic typing и type affinity.
Это одновременно преимущество и источник сюрпризов
Для небольшого приложения гибкость приятна.
Миграции проще.
Импорт данных удобнее.
Можно быстро менять модель.
Но в крупной бизнес-системе иногда хочется, чтобы база сама сказала:
Нет, здесь нельзя хранить это значение.
Например:
amountдолжен быть числом.
user_idдолжен соответствовать пользователю.
created_atдолжен иметь предсказуемую семантику.
Чем больше domain invariants можно надёжно закрепить в схеме, тем меньше неправильных состояний проходит дальше.
Но современный SQLite умеет STRICT tables
Поэтому утверждение:
SQLite вообще не умеет строгие типы
тоже устарело.
SQLite поддерживает STRICT tables, которые позволяют включить более жёсткий контроль типов для конкретной таблицы.
Например:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL
) STRICT;Это хороший пример того, почему сравнивать базы по старым мифам опасно.
Foreign Key есть в обеих системах
И PostgreSQL, и SQLite поддерживают внешние ключи.
Например:
users
↓
ordersМожно запретить заказ, ссылающийся на несуществующего пользователя.
В PostgreSQL referential integrity является обычной частью схемы и активно используется для поддержания связности данных.
Но у SQLite есть важный нюанс с foreign keys
В SQLite enforcement foreign key нужно явно контролировать.
В текущей документации указано, что foreign key constraints по умолчанию отключены для обратной совместимости и обычно включаются через:
PRAGMA foreign_keys = ON;для соединения. Разработчикам рекомендуют не полагаться на default и выставлять режим явно.
Это небольшая техническая деталь, но она способна создать серьёзные сюрпризы при переносе схем между БД.
Пример различий схемы
Для PostgreSQL можно написать:
CREATE TABLE projects (
id uuid PRIMARY KEY,
owner_id uuid NOT NULL
REFERENCES users(id),
status text NOT NULL,
budget numeric(12,2),
created_at timestamptz NOT NULL
);Здесь схема достаточно жёстко описывает данные.
В SQLite похожая бизнес-модель может выглядеть:
CREATE TABLE projects (
id TEXT PRIMARY KEY,
owner_id TEXT NOT NULL,
status TEXT NOT NULL,
budget NUMERIC,
created_at TEXT NOT NULL,
FOREIGN KEY(owner_id)
REFERENCES users(id)
) STRICT;Внешне SQL очень похож.
Но внутреннее поведение типов, дат, concurrency и runtime совершенно разное.
Поэтому ORM не делает базы полностью взаимозаменяемыми
Часто можно услышать:
У нас Prisma / Sequelize / SQLAlchemy / Hibernate, потом просто поменяем SQLite на PostgreSQL.
Иногда это действительно относительно просто.
Но чем взрослее проект, тем больше различий начинает просачиваться наружу.
Например:
типы дат;
JSON;
UUID;
decimal;
locking;
upsert;
индексы;
полнотекстовый поиск;
ALTER TABLE;
изоляция транзакций;
поведение concurrency.ORM скрывает часть синтаксиса.
Он не отменяет архитектурные свойства СУБД.
Особенно опасно разрабатывать на SQLite, а production запускать на PostgreSQL без реальных тестов
Например:
development → SQLite
production → PostgreSQLможет казаться удобным.
Но часть SQL и миграций ведёт себя по-разному.
То, что успешно работает локально, может не совпадать с production по:
типам;
constraints;
case sensitivity;
locking;
DDL.Если production использует PostgreSQL, очень часто проще и безопаснее использовать PostgreSQL и в development — например через Docker.
Где SQLite особенно хорош — локальное приложение
Представим desktop-приложение:
клиентская база;
заметки;
настройки;
локальная история.Есть один пользователь.
Данные должны находиться на его компьютере.
Запуск отдельного PostgreSQL server выглядит странно.
SQLite здесь почти идеален:
Application
+
data.sqliteТо же относится к мобильному приложению
Телефон должен работать:
без сети;
в самолёте;
в метро;
при нестабильном интернете.SQLite прекрасно подходит как локальный persistence layer.
Центральный сервер при этом вполне может использовать PostgreSQL.
Получается архитектура:
Mobile
↓
SQLite
↓
Sync
↓
API
↓
PostgreSQLТо есть выбирать между ними иногда вообще не требуется.
Они могут использоваться одновременно для разных задач.
Это особенно полезно в offline-first
Например:
SQLite
→ состояние на устройстве
PostgreSQL
→ центральная cloud-базаДальше уже возникает другой класс проблем:
sync;
conflicts;
three-way merge;
offline queue.Но сами базы отлично дополняют друг друга.
SQLite хорош и как локальный cache
Допустим основной источник истины:
PostgreSQLНо desktop client хочет быстро искать данные без постоянного запроса к серверу.
Можно использовать:
PostgreSQL
↓ sync
SQLite local cacheЭто официальный рекомендуемый сценарий использования SQLite: локальный cache для данных enterprise-системы.
А что насчёт backend небольшого сайта?
Здесь ответ уже интереснее.
Пример:
личный блог;
справочник;
небольшой каталог;
панель администратора.Один Node.js process.
Практически вся нагрузка:
SELECTSQLite вполне способен быть production-БД.
Его использование здесь не является «экономией на нормальной базе».
Это осознанное упрощение инфраструктуры.
Иногда SQLite даже быстрее
Если приложение и база находятся на одном компьютере, SQL выполняется внутри процесса без сетевого обращения к отдельному database server.
То есть нет:
application
↓
network protocol
↓
database processЕсть:
application
↓
SQLite library
↓
fileДля определённых локальных workload это может быть очень эффективно. Документация SQLite отдельно отмечает, что server-side приложение с сериализованными database requests может успешно использовать SQLite и получать очень хорошую производительность.
Поэтому вопрос «что быстрее?» почти бессмыслен
Можно провести benchmark:
SELECT 1и получить победителя.
Но реальное приложение делает:
JOIN;
transactions;
network calls;
JSON;
sorting;
writes;
locks.Правильнее спрашивать:
Какая архитектура лучше подходит нашей нагрузке?
SQLite может выигрывать на простой локальной работе.
PostgreSQL — на конкурентной централизованной системе.
Представим новый SaaS
План:
регистрация;
организации;
роли;
проекты;
сообщения;
оплата;
файлы;
уведомления.На старте пользователей:
20Кажется, SQLite достаточно.
Вероятно, технически да.
Но нужно посмотреть не только на сегодняшнюю нагрузку.
Важнее предполагаемая архитектура через год
Например, скоро появятся:
API #1
API #2
Worker
Scheduler
Webhook processorВсе они пишут в одну базу.
И далее:
1000 организаций;
несколько тысяч одновременных сессий;
фоновые jobs;
платёжные webhook.В таком случае мы бы чаще выбирали PostgreSQL с самого начала.
Не потому, что SQLite «не выдержит 1000 пользователей».
А потому, что целевая архитектура является многопроцессной системой с конкурентной записью.
Количество пользователей — плохой критерий выбора
Допустим есть приложение:
100 000 пользователейно каждый открывает его раз в месяц, в основном читает данные.
SQLite потенциально может чувствовать себя нормально.
Другой продукт:
100 пользователейно каждый постоянно:
обновляет сделки;
пишет сообщения;
запускает задачи.Здесь writer contention может быть намного выше.
Поэтому вопрос:
Сколько пользователей выдержит SQLite?
слишком примитивен.
Правильнее:
Какой concurrency profile у приложения?
Для CRM мы обычно предпочли бы PostgreSQL
Потому что CRM естественно содержит много связанных сущностей:
users;
companies;
contacts;
deals;
tasks;
messages;
documents;
audit.Одновременно работают разные сотрудники и background процессы.
Также полезны:
row locking;
transactions;
constraints;
advanced indexes;
JSONB;
full-text;
reporting.PostgreSQL здесь находится в своей естественной среде.
Для SaaS — тоже чаще PostgreSQL
Особенно если есть multi-tenancy:
Organization A
Organization B
Organization Cи множество одновременно работающих процессов.
Кроме concurrency появляются требования:
backup;
replication;
monitoring;
connection security;
roles;
PITR.PostgreSQL имеет развитый набор инструментов для такого production-контура.
Для интернет-магазина мы также чаще выбрали бы PostgreSQL
Особенно если существуют:
остатки;
заказы;
платежи;
webhook;
промокоды;
резервы.Потому что здесь важна не только скорость чтения каталога.
Есть конкурентные транзакционные операции.
Например:
два клиента
покупают последний товар.Именно здесь server-grade concurrency становится особенно ценной.
Для небольшого CMS SQLite вполне может быть лучшим
Допустим:
1 редактор;
200 статей;
10 000 посетителей;
редкие изменения.Если архитектура:
один backend
один VPSPostgreSQL может добавлять административную сложность практически без реальной пользы.
SQLite позволяет сократить количество moving parts.
Чем меньше компонентов, тем меньше точек отказа
SQLite:
Application
DiskPostgreSQL:
Application
Connection
PostgreSQL process
Configuration
Authentication
Database storageЭто не недостаток PostgreSQL.
Это цена возможностей.
Но если эти возможности проекту пока не нужны, простота SQLite имеет реальную ценность.
Backup SQLite выглядит очень привлекательно
Поскольку основная БД — файл, естественная мысль:
cp app.db backup.dbНо с работающей БД нужно быть аккуратнее.
Особенно в WAL mode нельзя бездумно копировать только основной .db, забывая о связанном WAL-состоянии.
SQLite предоставляет специальный Online Backup API и другие корректные способы создания snapshot работающей базы.
То есть:
SQLite — один файл
не означает:
backup всегда просто cp.Зато восстановление часто очень простое
В маленьком сервисе восстановление может сводиться к:
stop app
↓
restore database file
↓
start appЭто чрезвычайно удобно.
Для локальных продуктов такая простота трудно переоценить.
PostgreSQL backup сложнее, но и возможности существенно шире
У PostgreSQL существуют несколько подходов:
SQL dump;
filesystem/base backup;
continuous archiving;
PITR.Актуальная документация PostgreSQL отдельно описывает dump, файловые backup и непрерывное архивирование с Point-in-Time Recovery.
Что даёт PITR
Представим:
14:00
база нормальна
14:07
администратор случайно удалил данные
14:20
ошибка обнаруженаПри правильно настроенном continuous archiving можно восстановить состояние, например, ближе к:
14:06:59То есть до ошибочной операции.
Для серьёзного SaaS или CRM это очень полезная возможность.
pg_dump тоже остаётся удобным инструментом
Например:
pg_dump app > backup.sqlPostgreSQL способен создавать согласованный dump работающей базы без блокировки обычных readers/writers.
Но для больших production систем backup strategy обычно не должна ограничиваться одной командой раз в сутки.
Эксплуатация PostgreSQL требует больше внимания
Нужно следить за:
backup;
connections;
disk;
vacuum;
slow queries;
indexes;
memory;
updates.Если использовать managed PostgreSQL, часть работы берёт провайдер.
При self-hosted варианте ответственность лежит на владельце продукта.
SQLite в этом смысле значительно проще.
Но SQLite тоже не является базой «без эксплуатации»
Например, при WAL mode важно понимать checkpoint.
Если long-running readers постоянно мешают checkpoint завершиться, WAL способен заметно расти. Официальная документация отдельно описывает checkpoint starvation как потенциальную причину увеличения WAL.
То есть даже максимально простая СУБД требует понимания её operational model.
Масштабирование — один из главных водоразделов
Сегодня:
1 VPS
1 Node.js process
SQLiteВсё работает.
Завтра нужно:
Nginx
↓
API #1
API #2Где разместить database file?
Если он находится на:
API #1API #2 его не видит.
Можно начать строить shared storage.
Но тогда мы постепенно идём против естественной архитектуры SQLite.
Официальная документация SQLite сама рекомендует рассматривать клиент-серверную БД, если приложение стало настолько нагруженным или write-intensive, что требует нескольких серверов.
PostgreSQL для этого сценария естественен
API #1 ──┐
API #2 ──┼→ PostgreSQL
API #3 ──┤
Worker ──┘Database server является отдельным централизованным компонентом.
Масштабирование application layer не требует переноса database file между API-инстансами.
Но это не означает, что PostgreSQL автоматически решает масштабирование
При росте появятся:
connection pool;
slow queries;
indexes;
replication;
partitioning;
cache.Любая БД имеет пределы.
Разница в том, что PostgreSQL проектировался именно под такой путь развития.
Security-модель тоже отличается
SQLite — файл.
Основная граница доступа:
кто может открыть этот файл?Обычно безопасность обеспечивается:
правами ОС;
самим приложением;
шифрованием при необходимости.PostgreSQL имеет собственную server-side модель:
users;
roles;
permissions;
authentication;
network rules.Это удобно для централизованных корпоративных систем.
Но не нужно открывать PostgreSQL напрямую в интернет
Архитектура обычного веб-приложения:
Internet
↓
Backend API
↓
PostgreSQLа не:
Internet
↓
PostgreSQLКлиентский браузер не должен самостоятельно выполнять SQL.
Что насчёт JSON
Иногда SQLite выбирают потому, что:
У нас много JSON.
Или PostgreSQL:
У него есть JSONB.
Правда в том, что обе системы умеют работать с JSON.
Но PostgreSQL jsonb предоставляет зрелую систему операторов и индексирования, что особенно полезно, когда JSON становится частью сложных запросов.
При этом relational schema всё равно часто лучше для основного business domain.
Не нужно выбирать SQLite только для того, чтобы избежать схемы
Можно использовать SQLite очень дисциплинированно:
foreign keys;
STRICT tables;
constraints;
indexes;
migrations.И можно использовать PostgreSQL ужасно:
одна таблица;
jsonb everything;
никаких constraints.Качество данных определяется не только названием СУБД.
Индексы нужны обеим базам
Например:
SELECT *
FROM projects
WHERE organization_id = ?
ORDER BY created_at DESC;Если таблица выросла до миллионов записей, отсутствие индекса будет проблемой и в SQLite, и в PostgreSQL.
Выбор «более серьёзной» базы не исправляет плохую модель запросов.
PostgreSQL особенно интересен для аналитики внутри transactional продукта
Например CRM хочет запрос:
выручка по менеджерам
за 12 месяцев
с разбивкой по статусамили SaaS:
retention по организациям;
MRR;
churn;
cohort.Window functions, CTE, advanced aggregates и развитый query planner делают PostgreSQL очень удобным для сложной relational аналитики.
SQLite тоже поддерживает современные SQL-возможности, но для централизованного многопользовательского аналитического workload PostgreSQL обычно даёт больше пространства для роста.
Когда миграция с SQLite на PostgreSQL становится неприятной
Типичный сценарий:
SQLite сначала
«потом легко мигрируем»Проходит два года.
В базе:
миллионы записей;
десятки таблиц;
много миграций;
production 24/7.Теперь нужно переносить.
Появляются различия:
типы;
date/time;
boolean;
autoincrement;
constraints;
SQL expressions;
locking expectations.Плюс нужно выполнить data migration без долгого downtime.
Поэтому нужно заранее оценивать вероятность миграции
Если проект — локальный utility:
SQLite почти наверняка останется навсегда.Если это:
SaaS;
CRM;
маркетплейс;
финансовый сервис,и рост входит в бизнес-план, PostgreSQL с самого начала может быть дешевле, даже если первая версия технически могла работать на SQLite.
Но выбирать PostgreSQL «на будущее» тоже можно слишком рано
Представим маленький self-contained сервис, который всегда будет запускаться:
у одного клиента
на одном ПКВыбор PostgreSQL ради потенциального:
А вдруг однажды миллион пользователей
только усложнит:
installation;
deployment;
backup;
support.Архитектура должна соответствовать реальному будущему, а не максимально возможному воображаемому.
Сравним практические свойства
| Критерий | SQLite | PostgreSQL |
|---|---|---|
| Архитектура | Встроенная | Client/server |
| Отдельный DB server | Не нужен | Нужен |
| Основное хранение | Один database file | Управляемое PostgreSQL storage |
| Deployment | Очень простой | Сложнее |
| Concurrent reads | Хорошо | Хорошо |
| Concurrent writes | Один writer на DB file | Рассчитан на множество конкурентных транзакций |
| Несколько API-серверов | Неестественно для общего файла | Естественный сценарий |
| Локальное/offline приложение | Отлично | Обычно избыточно |
| CRM/SaaS | Возможно при ограниченной нагрузке | Обычно предпочтительнее |
| Strict typing | Есть через STRICT, но модель SQLite гибкая | Строгая |
| Backup | Очень простой, но нужно учитывать активную БД/WAL | Больше вариантов, включая PITR |
| Администрирование | Минимальное | Требуется |
| Масштабирование | Вертикальное/архитектурно ограниченное | Больше вариантов роста |
| Network DB | Не основной сценарий | Нормальный сценарий |
| Multi-process write load | Может стать bottleneck | Сильная сторона |
| Embedded/mobile | Сильная сторона | Не предназначен для этого |
Какую базу выбрать для конкретных типов проектов
Теперь самое практичное.
Небольшой сайт
Например:
контент;
форма обратной связи;
один администратор;
один backend.SQLite вполне разумен.
PostgreSQL тоже будет работать, но может быть избыточен.
Корпоративный сайт с экспертным разделом
Если это в основном:
страницы;
статьи;
редкая публикация;
формы.SQLite может быть достаточен.
Если уже появляются:
личные кабинеты;
CRM-функции;
background workers;
интеграции,PostgreSQL становится привлекательнее.
CRM
Чаще:
PostgreSQL.
Причины:
много пользователей;
много записей;
конкурентные обновления;
связанные бизнес-сущности;
audit;
отчёты.SaaS
Для обычного многопользовательского SaaS:
PostgreSQL.
Особенно если есть:
организации;
permissions;
billing;
jobs;
webhook;
несколько backend processes.Интернет-магазин
Для полноценного магазина с заказами, оплатой и остатками:
обычно PostgreSQL.
Каталог можно эффективно читать и из SQLite, но transactional часть делает клиент-серверную БД более естественным выбором.
Desktop-приложение
Чаще:
SQLite.
Отдельный PostgreSQL server на компьютере пользователя обычно не нужен.
Мобильное приложение
Для локальной базы:
SQLite.
Для центрального backend:
PostgreSQL или другая server DB.
Обе могут использоваться одновременно.
Offline-first приложение
Практичная комбинация:
SQLite
→ устройство
PostgreSQL
→ серверПлюс слой синхронизации.
Внутренний инструмент на одном сервере
Если:
5–20 пользователей;
небольшая write load;
один process;SQLite может быть отличным способом не усложнять инфраструктуру.
Самый полезный критерий выбора
Вместо:
Сколько будет пользователей?
мы бы задали пять вопросов.
| Вопрос | Если ответ «да» |
|---|---|
| Будет много одновременно пишущих процессов? | Склоняемся к PostgreSQL |
| Планируется несколько backend-инстансов? | PostgreSQL |
| База является локальным хранилищем одного приложения? | SQLite |
| Нужен минимальный deployment без DB-server? | SQLite |
| Это долгоживущий SaaS/CRM с активным ростом? | Обычно PostgreSQL |
Есть ещё один простой критерий
Представьте архитектуру продукта.
Если естественная схема:
Application
↓
local databaseскорее всего стоит серьёзно рассмотреть SQLite.
Если:
API #1
API #2
Worker
Scheduler
Webhook
\ | /
Databaseвероятнее всего естественным выбором будет PostgreSQL.
Когда мы бы не стали мигрировать с SQLite
Если система работает:
стабильно;
быстро;
один сервер;
низкая write concurrency.И никаких ограничений SQLite на практике нет, миграция только ради:
PostgreSQL считается серьёзнее
не имеет смысла.
Переписывание работающей инфраструктуры без измеримой причины — это технический риск и расходы.
Когда миграцию уже стоит планировать
Сигналы могут быть такими:
частые SQLITE_BUSY;
write contention;
нужно несколько серверов;
сложно координировать workers;
растёт downtime на операции;
нужна централизованная DB-security;
появляются требования к replication/PITR.Тогда вопрос уже не:
Что моднее?
А:
Текущая архитектура перестала соответствовать workload.
SQLITE_BUSY сам по себе ещё не означает срочную миграцию
Иногда проблема находится в приложении.
Например транзакция открывается:
BEGINзатем выполняется внешний HTTP-запрос:
10 секунди только потом:
COMMITWrite lock удерживается слишком долго.
Сначала стоит исправить транзакцию.
Если writers обычно завершаются за миллисекунды, SQLite способен справляться с большей нагрузкой, чем часто предполагают. Официальная документация SQLite тоже подчёркивает, что single-writer модель не является проблемой для множества обычных workload, где записи короткие и могут быстро идти по очереди.
PostgreSQL тоже не лечит плохие транзакции
Можно перейти на PostgreSQL и продолжить держать:
transactionоткрытой 30 секунд.
Появятся:
locks;
contention;
deadlocks.Технология не отменяет необходимость правильно проектировать работу с БД.
Что выбрать для нового сложного веб-продукта
Если мы проектируем с нуля:
CRM;
SaaS;
B2B-портал;
маркетплейс;
сервис заказов;
клиентский кабинетс ожидаемым ростом и несколькими backend-процессами, мы бы чаще начинали с PostgreSQL.
Не потому, что SQLite плох.
А потому что PostgreSQL лучше соответствует предполагаемой операционной модели.
А для небольшого и локального продукта мы бы выбрали SQLite без стеснения
Если задача:
небольшой сервис;
один процесс;
один сервер;
локальные данные;
минимум обслуживания,SQLite способен быть более качественным архитектурным решением именно благодаря своей простоте.
Использовать PostgreSQL только ради статуса «production-grade» здесь было бы странно.
SQLite тоже является полноценной production-технологией — просто для другого класса задач.
Самая дорогая ошибка — выбирать БД по репутации
Плохая логика:
PostgreSQL мощнее
→ всегда PostgreSQLили:
SQLite проще
→ зачем PostgreSQLПравильнее:
Какие данные?
↓
Кто пишет?
↓
Сколько writers?
↓
Где работает приложение?
↓
Нужны ли несколько серверов?
↓
Какие требования к backup?
↓
Каким станет продукт?И только потом:
SQLite или PostgreSQLВместо вывода
PostgreSQL и SQLite решают похожую задачу — хранение реляционных данных.
Но делают это из принципиально разных архитектурных предпосылок.
SQLite говорит:
Давайте встроим
надёжную SQL-базу
прямо в приложение
и уберём почти всю
инфраструктурную сложность.PostgreSQL:
Давайте создадим
централизованный database server,
который координирует работу
множества клиентов и транзакций.Обе идеи отличные.
Просто для разных случаев.
Если данные локальны, приложение работает на одном устройстве или одном сервере, concurrent writes невелики, а простота deployment действительно ценна — SQLite может оказаться лучшим выбором.
Если проект превращается в многопользовательскую CRM, SaaS, интернет-магазин или B2B-систему с несколькими API-процессами, workers, webhook и активной конкурентной записью — PostgreSQL обычно предоставляет более подходящий фундамент.
Поэтому мы бы не спрашивали:
«Какая база лучше?»
Мы бы спросили:
«Как будет жить и изменяться наш продукт через год после запуска?»
Если ответ на этот вопрос понятен, выбор между PostgreSQL и SQLite становится значительно проще.
И иногда самое профессиональное решение — выбрать не более мощную технологию, а ту, сложность которой действительно соответствует задаче.