<!-- Bothost docs | HTML: https://bothost.ru/docs/sqlite-data-lost | Markdown: https://bothost.ru/docs/sqlite-data-lost.md | Index: https://bothost.ru/llms.txt -->

# SQLite пропала и бот теряет данные после рестарта

Пользователи, заказы или сессии обнулились после перезапуска или обновления бота на Bothost. Файл базы при этом «создаётся заново» без ошибки. Ниже почему так происходит с SQLite и куда писать файл, чтобы он пережил деплой.

> **Для людей и ИИ.** Каноническая страница: https://bothost.ru/docs/sqlite-data-lost · Markdown: https://bothost.ru/docs/sqlite-data-lost.md · Индекс: https://bothost.ru/llms.txt
> Отвечает на запросы: SQLite database disappeared, bot loses data after restart, database reset after deploy, bot.db empty, data lost on reboot, /app/data.
> Как устроена папка и примеры создания таблиц: [хранение базы данных](database-storage).

---

## Что на Bothost сохраняется

Между пересборками сохраняется каталог **`/app/data`**. Он подключён отдельным томом. Платформа задаёт переменную `DATA_DIR=/app/data`.

Файл в другом месте живёт в слое контейнера или в каталоге, который при новом деплое заменяется кодом из Git:

- `/app/bot.db`, `./bot.db`, `database.sqlite` рядом со скриптом;
- `/tmp/...`;
- путь внутри репозитория, который приходит из коммита;
- база `:memory:`.

Кнопка перезапуска того же контейнера часто оставляет файлы на месте, поэтому кажется, что «вчера после рестарта всё было». Обновление из Git, загрузка нового архива и пересоздание контейнера заново собирают файловую систему кода. Том `/app/data` при этом остаётся, всё остальное пропадает. Пустая база выглядит как пропажа: SQLite не сообщает об ошибке, а создаёт новый файл.

Проверка в панели: откройте файловый менеджер бота и найдите базу именно в папке `data`. Если после сообщений пользователей файла там нет, процесс пишет мимо тома.

---

## SQLite database disappeared

### Относительный путь

```python
sqlite3.connect("bot.db")
```

Файл создаётся в текущем каталоге процесса. На Bothost это обычно `/app/bot.db`, а том смонтирован в `/app/data`. После деплоя в `/app` снова лежит код из репозитория, старого `bot.db` там нет, библиотека создаёт пустой.

Пишите в каталог данных:

```python
import os
import sqlite3
from pathlib import Path

data_dir = Path(os.environ.get("DATA_DIR", "/app/data"))
data_dir.mkdir(parents=True, exist_ok=True)
db_path = data_dir / "bot.db"

conn = sqlite3.connect(db_path)
conn.execute(
    "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)"
)
conn.commit()
```

Один и тот же путь должен быть во всех местах кода. Второй модуль со своим `connect("bot.db")` или `connect("/tmp/bot.db")` заводит другую, пустую базу, и кажется, что данные «то есть, то нет».

Задайте путь одной переменной в панели, если так удобнее читать код: `DATABASE_PATH=/app/data/bot.db`.

### База в Git затирает живые данные

Файл `bot.db` закоммичен в репозиторий. При обновлении код из Git копируется в приложение, и вместе с ним приезжает старая или пустая база из коммита. Папку `data` в Git не кладут. Добавьте в `.gitignore`:

```text
data/
*.db
*.sqlite
*.sqlite3
```

Живой файл храните только в `/app/data`. Если база уже была в корне репозитория, перенесите её один раз через файловый менеджер панели в `data`, поправьте путь в коде и уберите файл из коммита, иначе следующее обновление вернёт старую копию.

### :memory: и новый файл на каждый процесс

`sqlite3.connect(":memory:")` существует, пока живёт этот процесс. Рестарт контейнера начинает с пустой базы. То же самое делает код, который при каждом старте удаляет файл и создаёт таблицы заново без проверки. `CREATE TABLE IF NOT EXISTS` таблицу сохраняет. `DROP TABLE` и `os.remove(db_path)` при каждом запуске данные стирают, даже если путь правильный.

---

## bot loses data after restart

Файл в `/app/data` на месте, а последней записи нет.

**Не было commit.** `execute` без `commit()` держит изменение в транзакции. Процесс убили рестартом, транзакция откатилась. Фиксируйте изменения, которые нельзя потерять:

```python
conn.execute("INSERT INTO users (name) VALUES (?)", (name,))
conn.commit()
```

**Рядом лежат служебные файлы WAL.** При режиме WAL SQLite пишет `bot.db-wal` и `bot.db-shm`. Если скопировали в другое место только `bot.db`, последние записи остаются в `-wal`. Для работы на томе копировать ничего не нужно: все три файла и так в `/app/data`. В резервную копию забирайте каталог целиком, либо перед копированием выполните checkpoint.

**Рестарт случился в середине записи.** Короткая транзакция и `commit()` на каждое законченное действие уменьшают потерю до последней незафиксированной операции. Отдельный сервер MySQL или PostgreSQL имеет смысл, когда базы много и писателей несколько. Сам файл SQLite на томе `/app/data` для одного процесса бота как раз рассчитан на рестарты контейнера.

Права на каталог образ выставляет при сборке. Если в логе `attempt to write a readonly database` или `unable to open database file`, процесс не может создать файл в выбранном пути. Верните путь на `/app/data/...` и задеплойте снова. Разбор через терминал панели: [SQLite в терминале](sqlite-terminal).

---

## Как понять, что путь верный

1. В логе старта напечатайте абсолютный путь: `print(db_path)`.
2. Строка должна начинаться с `/app/data/`.
3. После сообщения боту файл виден в файловом менеджере в папке `data` и его размер больше нуля.
4. Сделайте обновление из Git или залейте новый архив и откройте ту же базу. Старые строки на месте.

Пока путь в логе `/app/bot.db` или `bot.db`, следующий деплой базу обнулит, даже если прямо сейчас после кнопки «перезапуск» данные ещё видны.

---

## См. также

- [Хранение базы данных](database-storage)
- [SQLite через терминал](sqlite-terminal)
- [Переменные окружения](environment-variables)
- [Падение после деплоя](works-locally-fails-on-server)

**Файл в `/app/data` есть, а записей нет?** Пришлите в поддержку строку пути из лога и момент, после которого данные пропали: [@bothostru](https://t.me/bothostru).
