Каждое развитие продукта — новый способ оплаты, программа лояльности, разделение таблицы — рано или поздно требует изменить структуру базы данных. В работающем приложении это самое рискованное место разработки: неудачная миграция может «уронить» сайт на часы или необратимо повредить данные клиентов. По разным оценкам, минута простоя интернет-магазина в час пик обходится в десятки тысяч рублей недополученной выручки. Хорошая новость: в связке NestJS + Prisma есть проверенный набор практик, который позволяет обновлять схему так, что пользователи ничего не замечают. Разберём их по шагам — от устройства миграций до плана отката.
Почему «ручные» правки базы — главный источник потерь
Типичная ситуация: разработчик открывает pgAdmin и добавляет колонку прямо в боевую базу «на пять минут». Через месяц никто не помнит, зачем она нужна, код перестаёт совпадать с реальной структурой, а новый релиз падает на чужом окружении. Это называется drift — расхождение схемы и кода, и именно оно становится причиной большинства аварийных простоев. Ручные правки не оставляют истории: невозможно узнать, кто, когда и зачем изменил таблицу, и невозможно откатить изменение. Миграции решают все четыре проблемы: каждое изменение — это версионированный файл в git, который применяется одинаково на всех окружениях.Как устроены миграции в Prisma
Prisma хранит схему данных в файле schema.prisma — это единый источник правды для всей команды. Команда prisma migrate dev создаёт из diff'а схемы SQL-миграцию и сохраняет её в папку prisma/migrations. На production применяется только prisma migrate deploy: она накатывает неприменённые миграции строго в порядке нумерации и ничего не «придумывает» сама. Критично не путать команды — prisma db push и migrate dev на боевом сервере запрещены: первая меняет схему без истории и может молча удалить данные, вторая может запросить интерактивный сброс. В NestJS-проектах миграции выносят в отдельный шаг CI/CD-пайплайна, а не запускают при старте приложения, иначе несколько инстансов попытаются изменить схему одновременно.Главный принцип: расширяй схему, не ломая старый код
Этот паттерн называют expand–migrate–contract: сначала расширяем схему, затем переносим данные и только в конце убираем устаревшее. Никогда не делайте разрушающие операции — переименование, смену типа, удаление — одним шагом: они требуют одновременного обновления всех копий приложения и остановки сервиса. Вместо этого разбейте изменение на серию обратно совместимых релизов:- Добавьте новое поле или таблицу, не трогая старые (nullable или со значением по умолчанию).
- Выкатите код, который пишет в новую структуру, но продолжает читать старую.
- Заполните исторические данные скриптом-бэкфиллом.
- Переключите чтение на новую структуру и сделайте деплой.
- Удалите устаревшие колонки только через 1–2 релиза, убедившись, что старый код нигде не остался.
Перенос данных: батчи вместо одного гигантского запроса
Классическая ошибка — заполнить новое поле для 10 миллионов строк одним UPDATE. Такой запрос держит блокировки, раздувает журналы транзакций и может «подвесить» продакшен на десятки минут. Правильный подход — фоновый бэкфилл-скрипт, который не мешает бизнесу:- Обрабатывайте данные батчами по 1 000–5 000 строк с паузой 50–100 мс между итерациями.
- Делайте скрипт идемпотентным: если он упал на середине, повторный запуск продолжает с того же места, а не начинает заново.
- Запускайте в часы минимальной нагрузки и логируйте прогресс: сколько строк обработано, сколько осталось.
- Для тяжёлых индексов в PostgreSQL используйте CREATE INDEX CONCURRENTLY — он строит индекс, не блокируя запись.
Порядок релиза: схема всегда раньше кода
Миграция должна применяться до старта новой версии приложения, а не после. Если код, который читает новое поле, окажется на серверах раньше самого поля, пользователи получат 500-е ошибки. В пайплайне шаг migrate deploy ставится перед деплоем контейнеров, и окружения проходятся по порядку: staging первым, production последним. Обязательно тестируйте миграцию на копии боевой базы: staging с базой на 1 000 строк не покажет, что UPDATE по 10 млн записей займёт 40 минут. Ещё одно правило: одна миграция — одна задача; не смешивайте в одном файле быстрое изменение схемы и долгую правку данных.Бэкапы и план отката — обязательный этап
Перед любой миграцией на продакшене делается бэкап, и не формально: проверьте, что из него реально можно восстановиться, и засеките время восстановления. Для PostgreSQL идеален PITR (point-in-time recovery) — в облачных провайдерах он включается одной галочкой. Заранее пропишите план отката: при обратно совместимых миграциях откат чаще означает «вернуть предыдущую версию кода», а не «перевернуть схему» — это быстрее и безопаснее. Prisma не поддерживает down-миграции из коробки, поэтому обратное изменение схемы пишут отдельной миграцией — и тоже прогоняют на staging, а не импровизируют в момент аварии.Пять ошибок, которые приводят к простою
Даже опытные команды регулярно наступают на одни и те же грабли. Проверьте, нет ли этих пунктов в вашем процессе:- prisma db push на продакшене — меняет схему без истории миграций и может молча удалить данные при расхождении.
- Правка уже применённой миграции — контрольная сумма не сойдётся, пайплайн упадёт; любое исправление вносится новой миграцией.
- Переименование колонки в один шаг — вместо этого делается связка «новая колонка + синхронизация данных + удаление старой».
- ALTER TABLE на большой таблице без учёта блокировок — в PostgreSQL многие изменения берут эксклюзивную блокировку и встают в очередь за всеми запросами, останавливая запись.
- Миграции при старте приложения — при нескольких инстансах они сработают одновременно; запускайте их отдельным шагом деплоя.
Что спросить у подрядчика про работу с базой
Даже если вы не погружаетесь в код, дисциплина миграций — точный индикатор зрелости команды. Спросите, как устроен процесс: где хранятся миграции, запускается ли migrate deploy в пайплайне, тестируется ли релиз на копии продакшена, есть ли бэкап и план отката перед каждым изменением схемы. Зрелая команда ответит конкретно и покажет историю миграций в репозитории; отговорки вида «мы правим базу напрямую, там всё просто» — повод насторожиться. Для бизнеса это не формальность: от этих процессов зависит, сколько минут в час пик ваш сайт будет недоступен и насколько безболезненно вы сможете развивать продукт.Вывод: безопасные изменения схемы — это не удача, а процесс: версионированные миграции Prisma, обратная совместимость по схеме expand–migrate–contract, батч-бэкфилл, деплой схемы до кода и проверенный бэкап. В связке NestJS + Prisma всё это автоматизируется в CI/CD и не требует останавливать приложение. Если ваши обновления до сих пор сопровождаются ночными окнами и нервами дежурного разработчика — самое время навести порядок. Наша команда настраивает пайплайны миграций и проводит аудит текущих схем: напишите нам, чтобы обсудить ваш проект.

