Бэкапы продакшена делают почти все, а локальную базу не бэкапит никто — до первой команды, которая стирает несколько часов ручной настройки тестовых данных. Надо ли бэкапить локальную базу? Да, и настраивается это за пару минут.
Почему локальные данные важнее, чем кажется
Продакшен обычно хоть как-то защищён: автоматические копии у облачного провайдера, мониторинг, алерты. Локальная среда остаётся без страховки.
Типичные сценарии потери данных на своей машине:
- миграция с ошибкой стёрла данные в нескольких таблицах;
- AI-агент (Cursor, Claude Code, Copilot) выполнил деструктивный SQL — подробнее в статье ИИ стёр базу данных: что делать;
docker compose down -vудалил тома вместе с данными;- случайный
rm -rfв директории проекта; - переустановка ОС без сохранения данных Docker;
- откат ветки в Git, хотя миграции уже применились к базе.
Что именно нужно бэкапить
- Схема (таблицы, индексы, триггеры) обычно уже версионирована миграциями (Alembic, Flyway, Prisma Migrate, Django migrations) и живёт в Git.
- Данные (строки в таблицах) — то, что действительно теряется.
- Seed-данные — отдельная тема, о ней ниже.
Бэкап SQLite
SQLite — один файл на диске, но копировать его через cp во время записи небезопасно: в режиме WAL часть транзакций ещё лежит в файле -wal, и копия получится несогласованной. Используйте встроенную команду .backup или VACUUM INTO — подробности в статье как сделать бэкап SQLite без повреждения.
mkdir -p backups
sqlite3 my_database.db ".backup 'backups/backup_$(date +%Y%m%d_%H%M%S).db'"
Команда использует online backup API и даёт согласованную копию даже при открытых соединениях. В режиме WAL она не мешает приложению писать.
Восстановление
Остановите приложение, затем:
sqlite3 my_database.db ".restore 'backups/backup_20260501_143000.db'"
Если восстанавливаете простым копированием файла, удалите рядом с базой старые my_database.db-wal и my_database.db-shm, иначе SQLite попытается применить к восстановленному файлу чужой журнал.
npm-скрипты
{
"scripts": {
"db:backup": "mkdir -p backups && sqlite3 app.db \".backup 'backups/backup_$(date +%Y%m%d_%H%M%S).db'\"",
"premigrate": "npm run db:backup"
}
}
Хук premigrate автоматически делает бэкап перед npm run migrate. Подстановка $(date ...) работает в bash/zsh; на Windows запускайте скрипт из Git Bash или WSL либо используйте PowerShell:
New-Item -ItemType Directory -Force backups | Out-Null
$ts = Get-Date -Format 'yyyyMMdd_HHmmss'
sqlite3 app.db ".backup 'backups/backup_$ts.db'"
Makefile
DB_FILE=app.db
BACKUP_DIR=backups
db-backup:
@mkdir -p $(BACKUP_DIR)
sqlite3 $(DB_FILE) ".backup '$(BACKUP_DIR)/backup_$(shell date +%Y%m%d_%H%M%S).db'"
@echo "Бэкап создан"
db-list:
@ls -la $(BACKUP_DIR)
Бэкап PostgreSQL
Базовый дамп
pg_dump -h localhost -U postgres -Fc -f backups/backup_$(date +%Y%m%d_%H%M%S).dump mydb
-Fc (custom-формат) создаёт сжатый архив, из которого можно восстанавливать отдельные таблицы. Человекочитаемый SQL:
pg_dump -h localhost -U postgres --format=plain -f backup.sql mydb
Восстановление
# custom-формат: только pg_restore
createdb -h localhost -U postgres mydb_restored
pg_restore -h localhost -U postgres -d mydb_restored backup.dump
# plain SQL: только psql
psql -h localhost -U postgres -v ON_ERROR_STOP=1 -d mydb_restored -f backup.sql
Все варианты восстановления — в статье как восстановить базу из бэкапа.
Пароль через .pgpass
Создайте ~/.pgpass (Linux/macOS) или %APPDATA%\postgresql\pgpass.conf (Windows):
localhost:5432:mydb:postgres:yourpassword
На Linux/macOS выставьте права chmod 600 ~/.pgpass, иначе файл будет проигнорирован.
Только данные или отдельные таблицы
# только данные — схема уже в миграциях
pg_dump -h localhost -U postgres --data-only -Fc -f data_only.dump mydb
# выбранные таблицы
pg_dump -h localhost -U postgres -t users -t orders -Fc -f selected_tables.dump mydb
Бэкап MySQL и MariaDB
mysqldump -u root -p --single-transaction --routines --triggers mydb > backup_$(date +%Y%m%d_%H%M%S).sql
-p без значения спросит пароль интерактивно — не пишите пароль прямо в команде, он будет виден в списке процессов. --single-transaction даёт согласованный снимок без блокировки таблиц, но только для InnoDB.
mysql -u root -p mydb < backup.sql
Бэкап MongoDB
mongodump --uri="mongodb://localhost:27017/mydb" --out=backups/$(date +%Y%m%d_%H%M%S)
mongorestore --uri="mongodb://localhost:27017" --drop backups/20260501_143000/
Docker и базы данных: частые ошибки
Ошибка №1: не понимать, что удаляет down -v
# Данные в анонимном томе: после down и нового up база окажется пустой
services:
db:
image: postgres:16
# Bind mount: данные лежат в папке проекта и переживают даже down -v
services:
db:
image: postgres:16
volumes:
- ./pgdata:/var/lib/postgresql/data
Важно: docker compose down -v удаляет и именованные тома, объявленные в compose-файле. Bind mount (./pgdata) он не трогает. Добавьте pgdata/ в .gitignore.
Бэкап из контейнера
# PostgreSQL: без флага -t, иначе TTY может испортить переводы строк в дампе
docker exec my_postgres pg_dump -U postgres mydb > backup.sql
# SQLite: сначала согласованная копия внутри контейнера, потом docker cp
docker exec my_app sqlite3 /app/database.db ".backup '/tmp/backup.db'"
docker cp my_app:/tmp/backup.db ./backups/backup_$(date +%Y%m%d_%H%M%S).db
Если в образе приложения нет sqlite3, остановите контейнер перед docker cp файла базы. Больше примеров — в статье бэкап БД в Docker и Coolify.
Восстановление в Docker
docker exec -i my_postgres psql -U postgres -v ON_ERROR_STOP=1 mydb < backup.sql
Seed-данные vs бэкап
| Критерий | Бэкап | Seed-скрипты | |---|---|---| | Совместимость со схемой | Может конфликтовать после миграций | Обновляются вместе с миграциями | | Передача коллеге | Нужна та же версия схемы | Достаточно запустить скрипт | | Воспроизводимость | Снимок конкретного момента | Одинаковый результат при каждом запуске | | Размер | Растёт вместе с данными | Небольшой, хранится в коде | | Назначение | Вернуть конкретное состояние | Стандартный набор тестовых данных |
Seed-скрипты — для стандартного набора тестовых данных, бэкапы — чтобы вернуть конкретное состояние после аварии.
# management/commands/seed.py
from django.core.management.base import BaseCommand
from myapp.models import User, Product
class Command(BaseCommand):
help = 'Seed database with test data'
def handle(self, *args, **options):
User.objects.get_or_create(email='admin@test.com', defaults={'name': 'Admin'})
Product.objects.bulk_create([
Product(name='Товар 1', price=100),
Product(name='Товар 2', price=200),
], ignore_conflicts=True)
self.stdout.write('База данных заполнена тестовыми данными')
Скрипт бэкапа для разработчика
#!/bin/bash
# db-backup.sh — запускайте из корня проекта
set -euo pipefail
BACKUP_DIR="./backups"
MAX_BACKUPS=10
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
if [ -f "app.db" ]; then
sqlite3 app.db ".backup '$BACKUP_DIR/sqlite_$TIMESTAMP.db'"
echo "SQLite бэкап создан"
fi
if command -v pg_dump >/dev/null 2>&1; then
if pg_dump -h localhost -U postgres -Fc -f "$BACKUP_DIR/pg_$TIMESTAMP.dump" mydb; then
echo "PostgreSQL бэкап создан"
else
echo "Ошибка pg_dump" >&2
rm -f "$BACKUP_DIR/pg_$TIMESTAMP.dump"
fi
fi
# Оставляем последние MAX_BACKUPS файлов каждого типа
ls -t "$BACKUP_DIR"/*.db 2>/dev/null | tail -n +$((MAX_BACKUPS+1)) | xargs -r rm -f
ls -t "$BACKUP_DIR"/*.dump 2>/dev/null | tail -n +$((MAX_BACKUPS+1)) | xargs -r rm -f
Инструменты
- DBeaver (бесплатный, все популярные СУБД) — экспорт в SQL, CSV, Excel, удобен для разовых ручных выгрузок. dbeaver.io
- TablePlus (macOS, Windows, Linux) — лёгкий клиент с быстрым экспортом, есть бесплатная версия. tableplus.com
- DataGrip (JetBrains, платный) — дампы с настройками, сравнение схем. jetbrains.com/datagrip
Версии локальной базы в dbsend
Если хочется хранить копии не только в папке backups/, а вне машины и с историей, подойдёт dbsend для SQLite. CLI сам делает согласованную копию SQLite-файла через VACUUM INTO, загружает её как новую версию и не создаёт дубль, если файл не изменился:
npm install --global @dbsend/sdk
dbsend login --key sqv_pk_...
dbsend init --database <id> --engine sqlite # создаст .dbsend.json без секретов
dbsend backup ./app.db -l before-migration
dbsend log
dbsend restore <snapshotId> ./app.restored.db --yes
Для PostgreSQL и MySQL загружается plain SQL-дамп (-e postgresql_dump или -e mysql_dump), сам дамп вы делаете pg_dump/mysqldump. Все команды — в документации CLI.
Правило 3-2-1 для локальной разработки
- 3 копии данных;
- 2 разных носителя (локальный диск + облако);
- 1 копия вне машины (облачный диск, S3).
Для разработки хватает упрощённой версии: копии в папке проекта и регулярная синхронизация с облаком.
Хранение бэкапов в облаке из командной строки
Google Drive через rclone
# разовая копия
rclone copy ./backups gdrive:dev-backups/myproject/
# зеркало папки: файлы, удалённые ротацией локально, удалятся и на Drive
rclone sync ./backups gdrive:dev-backups/myproject/
Яндекс Диск через WebDAV
curl -T backup.sql \
"https://webdav.yandex.ru/dev-backups/backup_$(date +%Y%m%d).sql" \
-u "login:app_password"
Используйте пароль приложения, а не основной пароль аккаунта.
Чеклист
- Перед любой миграцией — бэкап базы.
- Перед
docker compose down -v— проверьте, нужны ли данные из томов. - Перед экспериментами с данными — бэкап.
- После долгого наполнения базы тестовыми данными — бэкап.
- При активной разработке — автоматический бэкап раз в день.
- Раз в неделю проверяйте, что бэкап восстанавливается: см. как проверить, что бэкап рабочий.
Частые вопросы
Нужно ли бэкапить локальную базу, если в проекте есть миграции?
Да. Миграции восстанавливают схему, но не данные. Тестовые строки, которые вы вносили вручную, без бэкапа исчезнут.
Можно ли добавить SQLite-файл в Git?
Технически можно, но не стоит: бинарный файл плохо версионируется, а конфликты в нём не разрешить. Добавьте .db и .dump в .gitignore и пишите seed-скрипты.
Как быстро сделать бэкап PostgreSQL перед миграцией?
pg_dump -h localhost -U postgres -Fc -f pre_migration.dump mydb — одна команда. Для небольшой локальной базы она выполняется практически мгновенно.
Что делать, если docker compose down -v уже выполнен?
Если данные были в томе Docker, а не в bind mount, восстановить их, как правило, нельзя. На будущее держите данные в папке на хосте и делайте дамп перед опасными командами.
Сколько хранить локальные бэкапы?
Для активной разработки обычно хватает последних 5–10 копий — скрипт выше удаляет остальные автоматически.



