Первому приложению быстро становится тесно в переменных и JSON-файлах. Нужно хранить пользователей, рекорды, настройки или заказы так, чтобы данные не исчезали после перезапуска. Поднимать ради этого отдельный сервер базы данных часто рано, а SQLite закрывает промежуток между «сохранить пару значений» и полноценной облачной системой.
SQLite удобно поручить ИИ: ты описываешь, какие сущности нужны приложению, а Claude Code создаёт таблицы, запросы и проверку ошибок. Но выбрать подходящую базу всё равно должен ты. Для этого достаточно понимать, где находится файл, кто одновременно пишет в него и что случится с данными после деплоя.
Содержание
- Что такое SQLite простыми словами
- Чем SQLite отличается от PostgreSQL и Supabase
- Когда SQLite достаточно и когда пора переезжать на Postgres
- Как выглядит работа с SQLite в Node.js
- SQLite через Prisma или Drizzle
- DB Browser for SQLite: как посмотреть и поправить данные без кода
- SQLite и деплой: почему файл может пропасть
- Бэкап SQLite: копия файла с правильными условиями
- SQLite в браузере и телефоне
- Типичные ошибки новичка с SQLite
- Пример «Змейки»: localStorage, SQLite и Supabase
- Частые вопросы
- Что выбрать для первого приложения
Что такое SQLite простыми словами
SQLite — компактная реляционная база данных, которая работает прямо внутри приложения. Слово «реляционная» означает, что данные лежат в таблицах со строками и столбцами, а таблицы можно связывать между собой. Например, в одной таблице находятся игроки, в другой — их результаты, и каждый результат ссылается на конкретного игрока.
Обычная база данных часто устроена как отдельный сервис. Приложение обращается к нему по сети, отправляет запрос и получает ответ. SQLite не требует отдельного процесса-сервера: программа подключает библиотеку и читает файл, например snake.db, на том же компьютере.
Внутри одного файла помещаются:
- таблицы и строки с данными;
- описание столбцов и связей;
- индексы для быстрого поиска;
- служебная информация, необходимая для надёжной записи;
- представления и триггеры, если приложение их использует.
SQLite хранит данные не как читаемый текст. Открывать файл в обычном редакторе бессмысленно: ты увидишь набор непонятных символов и можешь повредить базу при сохранении. Для просмотра используют SQL-запросы, библиотеку приложения или программу SQLite Browser.
SQL — язык запросов к реляционным базам. Команда CREATE TABLE создаёт таблицу, INSERT добавляет строку, SELECT читает данные, а UPDATE меняет их. Базовые конструкции почти такие же, как в PostgreSQL. Поэтому знания из материала про SQL-запросы для новичка пригодятся и после перехода на другую базу.
Это зрелый движок, который встраивается в мобильные приложения, браузеры, настольные программы, устройства и системные компоненты. Он встречается почти в каждом телефоне и браузере, хотя конкретное приложение может использовать и другой способ хранения. Популярность объясняется простой поставкой: разработчику не нужно просить пользователя установить и настроить сервер.
SQLite привлекает сочетанием одного переносимого файла, транзакций и обычного SQL. Фраза «без сервера» при этом не означает «без серверного кода»: браузерная страница не должна напрямую открывать файл на диске хостинга. С SQLite обычно работает Node.js-приложение, настольная или мобильная программа.
Если понятия «таблица», «строка», «ключ» и «связь» пока смешиваются, сначала прочитай обзор баз данных для новичка. Для выбора SQLite достаточно запомнить короткое правило: один экземпляр приложения и один постоянный диск — хороший стартовый сценарий.
Чем SQLite отличается от PostgreSQL и Supabase
SQLite, PostgreSQL и Supabase решают похожую задачу хранения данных, но находятся на разных уровнях.
PostgreSQL — серверная система управления базами данных. Она запускается отдельным процессом, принимает сетевые подключения, управляет пользователями и хорошо обслуживает множество параллельных запросов. Подробнее её устройство разобрано в материале PostgreSQL для новичка.
Supabase — облачная платформа, в основе базы которой работает PostgreSQL. Кроме самой базы она даёт готовые возможности для авторизации, файлов, программного интерфейса и других частей приложения. Ты получаешь не новый вид SQL, а управляемую инфраструктуру вокруг Postgres. Актуальные тарифы смотри на сайте сервиса.
| Критерий | SQLite | PostgreSQL | Supabase |
|---|---|---|---|
| Где живёт база | В файле рядом с приложением или в указанной папке | В отдельном серверном процессе на своём или арендованном сервере | В облачном проекте Supabase; внутри работает PostgreSQL |
| Нужен ли отдельный сервер базы | Нет | Да | Платформа управляет им за тебя |
| Как приложение подключается | Открывает локальный файл через библиотеку | По сети, используя адрес и строку подключения | По сети через PostgreSQL или API платформы |
| Одновременная запись | Записи выполняются по очереди; в каждый момент активен один писатель | Рассчитан на множество параллельных подключений и писателей | Как у PostgreSQL, с ограничениями выбранной инфраструктуры |
| Чтение во время записи | Возможно при подходящем режиме журнала; долгие операции всё равно мешают друг другу | Хорошо поддерживает параллельную работу | Использует возможности PostgreSQL |
| Несколько серверов приложения | Файл пришлось бы безопасно делить между машинами, что обычно делает выбор неудачным | Все серверы подключаются к одной базе по сети | Все серверы обращаются к общей облачной базе |
| Публичное приложение с ростом нагрузки | Подходит не всегда; зависит от архитектуры и характера записи | Да | Да, если возможности проекта соответствуют нагрузке |
| Бэкап | Копия через встроенный механизм резервирования; при остановленном приложении можно копировать файл | Специализированные дампы, снимки и средства сервера | Управляемые возможности платформы и экспорт; условия зависят от тарифа |
| Администрирование | Минимальное | Нужно следить за сервером, доступом, обновлениями и резервированием | Часть работы берёт платформа |
| Удобный первый сценарий | Прототип, бот, локальная или настольная программа | Серверное приложение с несколькими процессами и пользователями | Публичный продукт, которому нужны общие данные и готовые облачные функции |
Главное различие не в размере проекта и не в «серьёзности» технологии. Оно в месте хранения и модели доступа. SQLite-файл принадлежит одной машине. PostgreSQL принимает подключения от разных машин. Supabase предоставляет PostgreSQL и связанные сервисы как готовую облачную среду.
SQLite умеет обслуживать много чтений и может быть очень быстрой, потому что между программой и данными нет сети. Ограничение проявляется при конкурирующей записи: движок сериализует изменения, то есть выполняет их по очереди. Для списка личных задач это незаметно. Для общего чата, куда непрерывно пишут пользователи через несколько серверов, это уже архитектурная проблема.
Supabase не требуется только потому, что приложение открывается в интернете. Небольшому Telegram-боту на одном сервере хватит SQLite при умеренной записи, постоянном диске и настроенных копиях. Но даже маленькому приложению нужен PostgreSQL, если оно запускается в нескольких экземплярах или делит данные между сервисами.
Когда SQLite достаточно и когда пора переезжать на Postgres
Выбирай базу по способу работы приложения, а не по страху «вдруг вырастет». Преждевременная сложность тоже стоит времени: отдельную базу нужно создать, защитить, подключить, обновлять и резервировать.
SQLite обычно достаточно для следующих задач.
Прототип
На раннем этапе нужно проверить идею и быстро менять структуру данных. Файл создаётся вместе с первым запуском, а лишнюю тестовую базу легко удалить и собрать заново. Ты тратишь время на поведение продукта, а не на инфраструктуру.
Локальный инструмент
Каталог документов, учёт домашних расходов, заметки, история обработанных файлов или небольшая система для одного сотрудника хорошо укладываются в один локальный файл. Данные не нужно передавать по сети, приложение продолжает работать без интернета.
Telegram-бот
SQLite подходит боту, который запущен в одном процессе на одном сервере: хранит настройки чатов, команды, напоминания или результаты турнира. Условие — файл лежит на постоянном диске, а второй экземпляр бота не пытается активно писать в ту же базу.
Настольное приложение
Установленная на компьютере программа может хранить базу в папке данных пользователя. Такой подход не требует регистрации и облака. Именно для встроенного локального хранения SQLite особенно удобна: приложение поставляется вместе с движком и само управляет своим файлом.
Автоматические тесты
Тесту нужна предсказуемая база, которую можно быстро создать с нуля. SQLite-файл или база в памяти позволяют подготовить таблицы, выполнить сценарий и убрать данные после проверки. Если рабочая среда использует Postgres, финальные тесты нужно запускать и на нём: у движков различаются типы, функции и параллельное поведение.
| Когда SQLite хватает | Когда пора переезжать |
|---|---|
| Приложение работает в одном процессе или на одной машине | Нужно запускать несколько экземпляров приложения на разных машинах |
| Большая часть операций — чтение, записи короткие и не конфликтуют | Пользователи часто и одновременно изменяют данные |
| База нужна локальному инструменту, боту или настольной программе | Разным сервисам нужен общий сетевой доступ к одним данным |
| Файл находится на постоянном диске | Платформа предоставляет только эфемерный диск без постоянного тома |
| Резервную копию файла легко хранить отдельно | Нужны централизованные роли, сложное управление доступом и развитая эксплуатация |
| Структура и запросы используют возможности SQLite | Приложение зависит от возможностей PostgreSQL или облачной платформы |
| Отказ одной машины допустим для сценария продукта | Нужна архитектура с высокой доступностью и переключением между узлами |
Сигнал к миграции — не определённое число строк. SQLite-база может быть большой, а маленькая таблица может создавать проблемы из-за сотен конкурентных записей. Смотри на симптомы и архитектуру:
- в журнале регулярно появляется
database is locked; - приходится запускать несколько копий серверной части;
- файл нужно синхронизировать между машинами;
- долгие записи задерживают запросы пользователей;
- команде нужен сетевой доступ с разными ролями;
- хостинг не гарантирует сохранность локального диска.
Переезд не нужно откладывать до аварии. Когда один из этих факторов становится частью ближайшего плана, попроси ИИ оценить несовместимые запросы, подготовить миграции, перенести данные на тестовой копии и сравнить результаты. Сначала делается резервная копия, затем пробный перенос, и только после проверки переключается рабочее приложение.
Как выглядит работа с SQLite в Node.js
Для Node.js есть несколько библиотек. В коротком примере используем better-sqlite3: у неё простой синхронный интерфейс, поэтому последовательность действий легко прочитать. Синхронный вызов означает, что программа ждёт завершения операции. Для небольшого приложения и коротких запросов это удобно; тяжёлую обработку и долгие запросы нельзя бездумно выполнять в основном потоке.
Сначала Claude Code может установить пакет:
npm install better-sqlite3
Создание файла базы
Подключение создаёт файл, если его ещё нет. Папка data должна существовать заранее.
const Database = require('better-sqlite3');
const db = new Database('data/snake.db');
db.pragma('journal_mode = WAL');
WAL — режим журнала предварительной записи. Он помогает чтениям меньше мешать записи, но не превращает SQLite в сервер с множеством одновременных писателей. Рядом с основным файлом во время работы могут появиться служебные файлы; удалять их вручную нельзя.
Создание SQLite-таблицы
Таблица рекордов хранит идентификатор записи, имя игрока, очки и время создания:
db.exec(`
CREATE TABLE IF NOT EXISTS scores (
id INTEGER PRIMARY KEY,
player_name TEXT NOT NULL,
score INTEGER NOT NULL CHECK (score >= 0),
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
)
`);
PRIMARY KEY делает id главным идентификатором, NOT NULL запрещает пустое значение, а CHECK — отрицательный результат. Ограничения защищают данные, даже если ошибётся другой участок программы. Для обычной таблицы запись INTEGER PRIMARY KEY не требует добавлять AUTOINCREMENT.
Вставка данных
Подготовленный запрос отделяет текст SQL от пользовательских значений:
const insertScore = db.prepare(`
INSERT INTO scores (player_name, score)
VALUES (?, ?)
`);
insertScore.run('Аня', 120);
Знаки ? — места для параметров. Не собирай запрос склеиванием строк вроде "... VALUES ('" + name + "')". Параметры правильно передают кавычки в имени и защищают от SQL-инъекции — ситуации, когда пользовательский ввод меняет смысл запроса.
Выборка рекордов
Команда ниже получает десять лучших результатов. Это не лимит SQLite, а правило примера — сколько строк показать на экране:
const topScores = db.prepare(`
SELECT player_name, score, created_at
FROM scores
ORDER BY score DESC, created_at ASC
LIMIT ?
`).all(10);
console.log(topScores);
Метод .all() возвращает массив строк. Для одной строки используют .get(), а для изменения данных — .run(). Если несколько изменений должны произойти вместе, попроси ИИ обернуть их в транзакцию: либо сохранятся все операции, либо ни одна.
Тот же ли SQL используется в PostgreSQL
Основы совпадают: CREATE TABLE, SELECT, INSERT, UPDATE, DELETE, WHERE, JOIN, ORDER BY и транзакции пригодятся после миграции. Простой запрос списка рекордов часто переносится почти без изменений.
Диалекты всё же различаются. PostgreSQL строже работает с типами, использует другие способы автоназначения идентификаторов, имеет собственные функции и возможности. Параметры в Node.js-драйвере PostgreSQL обычно записываются не как ?, а иначе. Даты, логические значения, JSON и изменение структуры таблиц требуют отдельной проверки.
Поэтому обещание «потом просто поменяем строку подключения» справедливо только для приложения, где различия спрятаны библиотекой доступа и схема совместима. Перед миграцией попроси Claude Code найти весь SQL, составить список несовместимостей и прогнать тесты на настоящем PostgreSQL.
SQLite через Prisma или Drizzle
better-sqlite3 позволяет писать SQL напрямую. Prisma и Drizzle добавляют слой между кодом приложения и базой: описание таблиц, миграции и программный интерфейс для запросов. Миграция — сохранённое изменение схемы, например создание таблицы или добавление столбца. Она позволяет повторить одинаковое изменение в локальной, тестовой и рабочей базе.
Такой инструмент полезен, если тебе проще просить ИИ работать с моделями User, Score и Game, чем проверять каждую SQL-строку. Но уникальность, обязательные поля, связи и индексы всё равно нужно сформулировать.
Prisma с SQLite
В конфигурации Prisma указывается поставщик SQLite и строка подключения к файлу:
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
Для локальной разработки значение подключения выглядит как путь с префиксом file::
DATABASE_URL="file:./dev.db"
Модели описываются в схеме Prisma, а клиент генерируется для приложения. При переходе на PostgreSQL меняются поставщик и строка подключения, создаётся миграция для новой базы и переносятся данные. Запросы уровня findMany или create часто сохраняются, если используются общие возможности обеих баз.
Однако смена базы не всегда сводится к одной строке. Типы полей, значения по умолчанию, собственный SQL и порядок миграций могут потребовать правок. Не переключай рабочую базу без тестового переноса и сверки количества записей.
Drizzle с SQLite
Drizzle ближе к SQL: таблицы описываются в TypeScript, а запросы строятся типизированными выражениями. Для SQLite можно использовать драйвер на основе better-sqlite3; для PostgreSQL потребуется другой драйвер и подключение.
const sqlite = new Database('data/app.db');
const db = drizzle(sqlite);
Основная бизнес-логика может остаться общей, если операции с базой собраны в отдельном модуле: например, saveScore() и getLeaderboard(). Prisma даёт более абстрактный клиент, а Drizzle оставляет модель ближе к SQL. Для нескольких коротких запросов прямой better-sqlite3 может быть понятнее обоих вариантов.
Что попросить у Claude Code
Хорошая задача описывает не библиотеку, а результат и ограничения. Например:
Подключи SQLite к Node.js-приложению через better-sqlite3. Храни файл в data/app.db, создай миграцию для таблицы scores с полями id, playerName, score, createdAt. Все пользовательские значения передавай параметрами. Добавь функции сохранения результата и чтения десяти лучших результатов, транзакцию там, где меняются несколько таблиц, и тесты на временной базе. Не добавляй файл базы в Git. Объясни, какие файлы изменил и как проверить работу.
Для Prisma или Drizzle замени название библиотеки и добавь требование: «Отдели доступ к данным от обработчиков, чтобы позже перейти на PostgreSQL». Если переход уже планируется, попроси использовать только совместимые типы и перечислить места, завязанные на SQLite.
После ответа проверь путь к файлу, параметры запросов, способ создания схемы и закрытие соединения. Фраза «один код, смена базы через строку подключения» описывает цель архитектуры, а не автоматическую гарантию: ORM сохраняет большую часть вызовов, но миграцию данных и различия движков нужно проверить.
DB Browser for SQLite: как посмотреть и поправить данные без кода
DB Browser for SQLite — настольная программа с графическим интерфейсом для файлов SQLite. В поиске её часто называют SQLite Browser или db browser for sqlite. Она помогает открыть базу, увидеть список таблиц, выполнить запрос и вручную поправить строку без написания отдельной административной страницы.
Программа полезна для диагностики:
- проверить, создалась ли SQLite-таблица;
- увидеть, сохранился ли новый рекорд;
- найти строку с неожиданным значением;
- выполнить простой
SELECT; - посмотреть структуру столбцов и индексов;
- исправить тестовые данные во время локальной разработки.
Общая последовательность не зависит от версии интерфейса:
- Останови приложение или работай с копией базы.
- Открой нужный
.db-файл в DB Browser for SQLite. - Посмотри структуру таблиц и нужные строки.
- Если меняешь данные, проверь условие выбора строки до сохранения.
- Сохрани изменения и снова запусти приложение.
Названия кнопок и расположение вкладок могут меняться, поэтому точные шаги интерфейса лучше сверять с текущей документацией программы. Для рабочих данных безопаснее скачать резервную копию и изучать её локально. Ручное исправление единственного файла на сервере без копии превращает небольшую опечатку в риск потери базы.
Не открывай один файл одновременно несколькими редакторами. Графическая программа может держать транзакцию, пока Node.js пытается записать результат, и тогда появится database is locked. После просмотра закрой файл, особенно перед запуском тестов и деплоем.
SQLite и деплой: почему файл может пропасть
Локально всё выглядит надёжно: ты перезапускаешь Node.js, а app.db остаётся на диске. На хостинге жизненный цикл файлов может быть другим. Многие платформы запускают приложение в контейнере — изолированном окружении, которое можно удалить и собрать заново при обновлении, сбое или переносе на другую машину.
Диск внутри такого контейнера часто эфемерный, то есть временный. Приложение записало рекорд в /app/data/app.db, затем платформа пересобрала контейнер, и новый экземпляр стартовал из исходного образа без созданного файла. Код сохранился в репозитории, а пользовательские данные исчезли.
Для SQLite на сервере нужен постоянный том — область хранения, чей срок жизни не связан с конкретным контейнером. Приложение должно открывать базу именно по пути внутри подключённого тома. Общая логика деплоя выглядит так:
- Уточнить, сохраняет ли платформа локальные файлы между перезапусками и обновлениями.
- Создать постоянное хранилище, если оно поддерживается.
- Передать путь к базе через настройку окружения, а не зашивать случайный путь в код.
- Убедиться, что каталог существует и доступен процессу на запись.
- Перезапустить приложение и проверить, что тестовая запись осталась.
- Настроить резервное копирование за пределы этого тома.
Названия разделов зависят от хостинга. Для Amvera общая логика публикации разобрана в материале про деплой для новичка, а актуальные настройки и тарифы смотри на сайте сервиса.
Постоянный том решает сохранность при пересборке, но не делает файл общим для любого количества серверов. Если платформа запустит две независимые копии приложения с разными томами, у каждой будет собственная база. Если обе машины пишут в сетевой файловый ресурс, блокировки и гарантии файловой системы могут не соответствовать ожиданиям SQLite.
Для горизонтального масштабирования — запуска нескольких экземпляров приложения — обычно выбирают PostgreSQL или Supabase. Все экземпляры подключаются к одной базе по сети, а сама база управляет конкурентной работой.
После деплоя создай отличимую тестовую запись, штатно перезапусти или обнови сервис и убедись, что запись сохранилась. Одна зелёная страница в браузере не подтверждает сохранность базы.
Бэкап SQLite: копия файла с правильными условиями
Резервная копия SQLite действительно проще, чем у многих серверных баз: результатом может быть второй .db-файл. Но копировать рабочий файл обычной файловой командой в случайный момент опасно. Пока соединение открыто, часть актуальных изменений может находиться в журнале, а запись — выполняться прямо во время копирования.
Есть три безопасных сценария.
Остановить приложение и скопировать файл
Самый понятный вариант для небольшого проекта:
- Штатно остановить процесс, чтобы он закрыл соединение.
- Убедиться, что запись больше не идёт.
- Скопировать основной файл базы в отдельное место.
- Запустить приложение снова.
- Периодически проверять восстановление из копии.
Этот способ создаёт короткий перерыв в работе, зато его легко объяснить и проверить.
Использовать команду .backup
Официальная консольная программа sqlite3 умеет сделать согласованную копию через встроенный механизм:
sqlite3 data/app.db ".backup 'backups/app.db'"
Каталог для копии должен существовать. Имя файла лучше дополнять датой и временем, но генерировать его должен скрипт с понятными правилами. Команда подходит для автоматизации без ручного открытия DB Browser.
Использовать API библиотеки
Многие библиотеки предоставляют функцию резервного копирования. У better-sqlite3 есть соответствующий программный метод, который можно вызвать из служебного скрипта. Это удобнее, когда копия создаётся по расписанию и приложение продолжает работать.
Бэкап не должен лежать только рядом с оригиналом. Если сломается диск, удалится том или будет потерян сервер, оба файла пропадут вместе. Копию хранят в другом месте с ограниченным доступом и понятным сроком хранения.
Наличие файла ещё не доказывает, что данные восстановятся. Попроси Claude Code создать отдельную команду проверки: открыть копию, проверить целостность и прочитать критичные таблицы, не касаясь рабочей базы.
SQLite в браузере и телефоне
Слово «локально» обозначает разные среды. SQLite внутри Node.js на сервере, хранилище браузерной страницы и база мобильного приложения не являются одним общим файлом.
localStorage и SQLite
localStorage — встроенное хранилище браузера для строковых значений. Оно удобно для настройки звука, выбранного скина или личного рекорда «Змейки» на одном устройстве. Данные привязаны к сайту и профилю браузера. Пользователь может очистить их, другой браузер их не увидит, а сервер не получает к ним автоматического доступа.
SQLite хранит таблицы, поддерживает SQL, индексы, связи и транзакции. Но обычный сайт не может взять Node.js-библиотеку better-sqlite3 и открыть произвольный файл на компьютере посетителя: браузер специально ограничивает доступ страницы к файловой системе.
Если нужно понять границы простого браузерного хранения, прочитай материал как работает localStorage.
IndexedDB
IndexedDB — встроенная браузерная база для более сложных локальных данных. Она умеет хранить структурированные объекты и подходит для офлайн-работы, очереди несинхронизированных действий, кэша и заметного объёма клиентских данных. У неё другой программный интерфейс: это не обычная SQLite-база и не прямой SQL.
Для PWA, которая должна работать без сети, часто используют IndexedDB, а после подключения синхронизируют изменения с серверной базой. Конфликты синхронизации нужно проектировать отдельно: что делать, если один пользователь изменил запись на двух устройствах.
SQLite в браузере
Браузеры сами могут использовать SQLite во внутренних компонентах — например, для истории или служебных данных. Это не даёт открытому сайту прямого доступа к внутренней базе браузера.
Существуют сборки SQLite для WebAssembly, которые запускают движок внутри веб-страницы. Они полезны для специализированных офлайн-приложений и обработки локальных наборов данных, но требуют продуманного сохранения между сеансами. Для первого сайта localStorage или IndexedDB обычно проще, а общие пользовательские данные всё равно хранятся на сервере.
SQLite в телефоне
Мобильные операционные системы и фреймворки предоставляют приложениям способы использовать SQLite или оболочки над ним. База находится в закрытой области конкретного приложения. Другие приложения не получают к ней свободный доступ, а удаление приложения обычно удаляет и его локальные данные.
Локальная мобильная SQLite подходит для истории, каталога, офлайн-кэша и пользовательских настроек. Если данные должны появиться на другом телефоне или быть общими для всех игроков, нужна синхронизация с сервером. Одна локальная база не превращается в облачную только потому, что телефон подключён к интернету.
| Задача | Подходящее хранилище |
|---|---|
| Пара настроек и личный рекорд в браузере | localStorage |
| Сложные офлайн-данные веб-приложения | IndexedDB или специализированное решение на базе WebAssembly |
| Таблицы внутри Node.js-бота на одном сервере | SQLite на постоянном диске |
| Локальные данные настольной или мобильной программы | SQLite |
| Общая таблица для пользователей с разных устройств | Серверная PostgreSQL или Supabase |
Типичные ошибки новичка с SQLite
Большинство проблем связано не со сложным SQL, а с тем, где находится файл и сколько процессов к нему обращаются.
Файл базы попал в Git
Рабочий .db-файл меняется при каждом действии пользователя. Если добавить его в репозиторий, в истории могут навсегда остаться имена, адреса, токены или другие данные. Git плохо подходит и для частых изменений бинарного файла: он не покажет понятное сравнение строк базы.
Добавь путь к базе и служебным файлам SQLite в .gitignore, а структуру храни в миграциях. Пример данных для разработки создавай отдельным скриптом.
data/*.db
data/*.db-wal
data/*.db-shm
Уже добавленный в Git файл не перестанет отслеживаться только из-за .gitignore. Попроси ИИ проверить git status и список отслеживаемых файлов, убрать базу из индекса без удаления локальной копии и убедиться, что в истории не оказалось секретов. Если чувствительные данные уже попали в удалённый репозиторий, одной новой правки недостаточно: доступы нужно заменить, а очистку истории выполнить отдельно и осознанно.
database is locked при двух процессах
SQLite блокирует конфликтующие операции, чтобы не повредить данные. Ошибка часто появляется, когда запущены две копии бота, DB Browser оставил незавершённое изменение или долгий запрос удерживает транзакцию.
Не лечи проблему бесконечным увеличением ожидания. Сначала выясни, кто открыл файл:
- закрой DB Browser;
- проверь, не запущен ли второй Node.js-процесс;
- сократи транзакции и не выполняй внутри них сетевые запросы;
- убедись, что соединения закрываются;
- настрой разумное ожидание занятой базы и режим WAL;
- если параллельная запись является нормой продукта, переходи на PostgreSQL.
WAL улучшает сочетание чтения и записи, но один момент записи всё равно обслуживается последовательно. Два контейнера с разными локальными файлами создают другую проблему: блокировки нет, зато данные расходятся.
Нет индексов
Без индекса база ищет подходящие строки просмотром таблицы. На маленьком наборе это незаметно, поэтому ошибка проявляется после накопления данных. Индекс нужен столбцам, по которым часто фильтруют, связывают и сортируют.
Для таблицы рекордов может пригодиться индекс по очкам и времени:
CREATE INDEX IF NOT EXISTS idx_scores_leaderboard
ON scores (score DESC, created_at ASC);
Каждый индекс занимает место и замедляет запись, потому что его тоже нужно обновлять. Не проси ИИ «добавить индексы на всё». Дай список реальных запросов и попроси предложить минимальный набор, а затем проверить план выполнения.
Картинки и большие файлы хранятся внутри базы
SQLite умеет хранить двоичные данные в столбце BLOB, но это не означает, что туда нужно складывать все изображения и видео. База разрастается, резервные копии становятся тяжёлыми, а раздача файлов усложняется.
Для аватаров, скриншотов и вложений чаще удобнее файловая система или объектное хранилище. В SQLite остаются путь, адрес, размер, тип и связь с владельцем. Небольшой двоичный объект можно хранить в базе, если это осознанно упрощает цельный перенос приложения, но решение нужно принимать по реальному сценарию.
Пример «Змейки»: localStorage, SQLite и Supabase
Хранилище «Змейки» меняется вместе со сценарием продукта. Три этапа показывают, почему не существует одной лучшей базы на все случаи.
Этап 1. Личный рекорд в localStorage
Первая версия игры открывается в браузере и запоминает лучший результат одного человека. Сервер не нужен. После партии код сравнивает очки с сохранённым значением и обновляет localStorage.
Плюсы такого решения — минимум кода и работа без сети. Ограничения тоже ясны: рекорд остаётся в конкретном профиле браузера, может исчезнуть после очистки данных и не появляется на другом устройстве.
На этом этапе SQLite ничего не улучшает. Подключать сервер только ради одного локального числа — лишняя инфраструктура.
Этап 2. Локальная SQLite для бота-турнира
Появляется Telegram-бот, который принимает результаты участников закрытого турнира. Бот работает одним процессом на сервере с постоянным диском. Теперь нужны таблицы игроков, матчей и результатов, сортировка, защита от повторной отправки и история партий.
SQLite хорошо совпадает с архитектурой: один процесс пишет в один файл, SQL строит таблицу лидеров, а резервная копия создаётся штатным механизмом. Администратор может открыть копию в DB Browser for SQLite и проверить спорную запись.
Для честности турнира нельзя доверять очкам, которые прислал изменённый браузерный код. База сохраняет полученное значение, но не доказывает, что партия сыграна по правилам. Проверка результата — отдельная задача серверной логики.
Этап 3. Supabase для общей таблицы
Игра становится публичной. Пользователи входят в аккаунты с телефонов и компьютеров, общая таблица обновляется через несколько экземпляров приложения, нужны правила доступа и синхронизация. Локальный файл одного бота превращается в узкое место.
На этом этапе данные переносятся в Supabase. Серверные части и разрешённые клиенты обращаются к общей PostgreSQL-базе, а платформа помогает с авторизацией и программным интерфейсом. Миграция включает создание схемы, перенос строк, проверку связей и переключение приложения.
Путь выглядит так:
| Версия продукта | Где данные | Почему этого хватает | Сигнал к следующему этапу |
|---|---|---|---|
| Браузерная игра | localStorage пользователя |
Один личный рекорд, сервер не нужен | Нужна общая таблица участников |
| Бот-турнир | SQLite на постоянном диске | Один процесс, таблицы и SQL, простой бэкап | Несколько серверов, аккаунты и частая общая запись |
| Публичная игра | Supabase с PostgreSQL | Общие данные, сетевой доступ и облачные функции | Следующий выбор зависит от нагрузки и требований продукта |
Не нужно начинать сразу с третьего этапа «на будущее». Полезнее выбрать минимальное хранилище, которое честно выполняет текущую задачу, и заранее отделить функции работы с данными. Тогда рост продукта приводит к плановой миграции, а не к переписыванию всей игры.
Частые вопросы
SQLite — это бесплатная база данных?
SQLite можно использовать без покупки отдельного сервера базы. Расходы могут появиться за хостинг приложения, постоянный диск, резервные копии и обслуживание. Условия конкретной платформы меняются, поэтому актуальные тарифы смотри на сайте сервиса.
Как открыть файл db SQLite?
Открой копию файла в DB Browser for SQLite или используй консольную программу sqlite3. Обычный текстовый редактор не подходит. Перед ручными изменениями останови приложение либо работай с резервной копией.
Подходит ли SQLite для сайта?
Да, если серверная часть работает на одной машине, запись умеренная, а файл лежит на постоянном диске. Для нескольких серверов, частой конкурентной записи и общей облачной инфраструктуры обычно выбирают PostgreSQL.
Сколько данных выдерживает SQLite?
Оценивать нужно не только размер файла. На практике раньше могут помешать одновременные записи, медленные запросы, отсутствие индексов или ограничения хостинга. Проверь характер нагрузки и не придумывай порог по числу пользователей.
Можно ли потом перейти с SQLite на PostgreSQL или Supabase?
Да. Проще всего переносить проект, если доступ к данным отделён от интерфейса, изменения схемы оформлены миграциями, а запросы покрыты тестами. ORM сохраняет часть кода, но совместимость типов, SQL и сами данные нужно проверить.
Что выбрать новичку: better-sqlite3, Prisma или Drizzle?
Для нескольких понятных запросов подойдёт better-sqlite3. Prisma удобна моделями и высокоуровневым клиентом, Drizzle держит код ближе к SQL. Выбирай один инструмент под текущий стек и попроси ИИ объяснить структуру, миграции и способ проверки.
Что выбрать для первого приложения
Бери SQLite, когда приложению нужна настоящая таблица, но данные принадлежат одному процессу и одному постоянному диску. Это естественный выбор для прототипа, локального инструмента, настольной программы, тестов и небольшого бота.
Сразу выбирай PostgreSQL или Supabase, если приложение запускается на нескольких серверах, пользователи часто пишут одновременно или данные должны быть общей сетевой точкой для разных сервисов. Решение определяет архитектура, а не престиж технологии.
Минимальный безопасный набор для SQLite — миграции, параметры в запросах, индексы под реальные выборки, файл вне Git, постоянный диск на сервере и проверяемый бэкап. С этими условиями база данных SQLite даёт первому приложению простое хранение без отдельного сервера и оставляет понятный путь к Postgres, когда он действительно понадобится.
Читай дальше
Все статьиНе просто статьи — тебя доведут до результата
В практикуме за 2499 ₽ рядом живая команда практикующих разработчиков и маркетологов: ведём по шагам до твоего работающего приложения. Не «ролики и сам разбирайся» — помогаем на каждом затыке.
Перейти к практикуму