Пошук уроків, статей та іншого контенту
Створимо, застосуємо та відкочуватимемо міграції для синхронізації схеми Prisma і бази даних.
Міграція — це версійна інструкція для зміни структури бази даних.
У проєкті з NestJS і Prisma схема описується у файлі prisma/schema.prisma. Після зміни цієї схеми Prisma створює міграцію — набір SQL-команд, які потрібно виконати над базою даних.
Наприклад, додавання поля:
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
createdAt DateTime @default(now())
}може перетворитися на SQL-команду на кшталт:
ALTER TABLE "User" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;Міграції потрібні, щоб:
синхронізувати schema.prisma і базу даних;
зберігати історію змін структури бази;
відтворювати однакову структуру бази на різних середовищах;
застосовувати зміни в CI/CD і production;
розуміти, як саме змінювалася база даних.
Припустімо, що Prisma вже встановлено в NestJS-проєкті, а файл .env містить рядок підключення:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/nest_app?schema=public"У prisma/schema.prisma повинні бути налаштовані генератор клієнта і джерело даних:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}Поле provider залежить від бази даних:
postgresql — PostgreSQL;
mysql — MySQL;
sqlite — SQLite;
sqlserver — Microsoft SQL Server;
cockroachdb — CockroachDB.
Перед виконанням міграцій база даних має бути доступною за адресою з DATABASE_URL.
Для створення міграції використовується команда:
npx prisma migrate dev --name initКоманда виконує кілька дій:
порівнює поточну Prisma-схему зі структурою бази;
створює нову директорію міграції;
генерує файл migration.sql;
застосовує міграцію до бази даних;
оновлює таблицю _prisma_migrations;
генерує Prisma Client.
Після цього структура проєкту може виглядати так:
prisma/
├── migrations/
│ ├── 20260901120000_init/
│ │ └── migration.sql
│ └── migration_lock.toml
└── schema.prismaНазва директорії містить часову мітку та назву міграції. Не слід перейменовувати або редагувати вже застосовані міграції без чіткої причини.
migration.sqlДля PostgreSQL перша міграція може мати такий вигляд:
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"email" TEXT NOT NULL,
"name" TEXT,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");Цей файл створюється Prisma автоматично. Його варто переглядати перед застосуванням, особливо якщо зміни стосуються важливих таблиць або великого обсягу даних.
Змінимо модель User і додамо модель Post:
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
@@index([authorId])
}Тепер створимо нову міграцію:
npx prisma migrate dev --name add-postsPrisma створить окремий каталог, наприклад:
prisma/migrations/
├── 20260901120000_init/
│ └── migration.sql
└── 20260901121500_add_posts/
└── migration.sqlКожна міграція повинна містити одну логічну групу змін. Назва add-posts пояснює її призначення краще, ніж назва на кшталт update-db.
migrate dev і migrate deploymigrate devКоманда:
npx prisma migrate devпризначена для локальної розробки.
Вона може:
створювати нові міграції;
застосовувати незастосовані міграції;
виявляти розбіжності між історією міграцій і базою;
у деяких ситуаціях пропонувати скинути локальну базу;
генерувати Prisma Client.
Прапорець --name використовується під час створення нової міграції:
npx prisma migrate dev --name add-user-statusmigrate deployКоманда:
npx prisma migrate deployпризначена для staging і production.
Вона:
знаходить міграції, яких ще немає в базі;
застосовує їх у правильному порядку;
не створює нових міграцій;
не скидає базу даних;
не використовує інтерактивний режим для створення міграції.
Зазвичай міграції створюють і перевіряють локально, додають папку prisma/migrations до репозиторію, а під час розгортання виконують:
npx prisma migrate deploy
npx prisma generateprisma generate може виконуватися під час встановлення залежностей або збірки проєкту, але явний виклик у deployment-скрипті робить цей крок очевидним.
Щоб перевірити стан міграцій, використовується:
npx prisma migrate statusКоманда показує:
які міграції вже застосовані;
які міграції очікують застосування;
чи є міграції, присутні в базі, але відсутні в локальній файловій системі;
чи є розбіжності між історією міграцій і поточною схемою.
Prisma зберігає інформацію про застосовані міграції у службовій таблиці _prisma_migrations. Не потрібно змінювати цю таблицю вручну.
Після застосування міграцій Prisma Client можна використовувати у сервісі NestJS:
import { Injectable } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Injectable()
export class UsersService {
constructor(private readonly prisma: PrismaService) {}
async create(email: string, name?: string) {
return this.prisma.user.create({
data: {
email,
name,
},
});
}
async findAll() {
return this.prisma.user.findMany({
orderBy: {
id: 'desc',
},
});
}
}Наприклад, послідовність команд для локальної розробки може бути такою:
# Створити міграцію та застосувати її до локальної бази
npx prisma migrate dev --name init
# Запустити NestJS у режимі розробки
npm run start:devЯкщо модель змінюється:
# Після редагування prisma/schema.prisma
npx prisma migrate dev --name add-user-status
# Перевірити стан міграцій
npx prisma migrate statusМіграції повинні бути частиною коду проєкту. До репозиторію потрібно додавати:
prisma/schema.prisma
prisma/migrations/Типова послідовність у production:
npm ci
npx prisma generate
npx prisma migrate deploy
npm run build
npm run start:prodВажливо, щоб DATABASE_URL у production вказував на production-базу, а не на локальну або тестову.
Команду migrate dev не слід використовувати в production, оскільки вона призначена для інтерактивної розробки та може запропонувати скидання бази.
Prisma Migrate не створює автоматичні down-міграції. Тобто для кожної міграції Prisma не генерує готову команду, яка гарантовано поверне базу до попереднього стану.
Безпечний спосіб скасувати вже застосовану зміну — створити нову міграцію, яка виконує зворотну зміну.
Наприклад, спочатку було додано поле:
model User {
id Int @id @default(autoincrement())
email String @unique
nickname String?
}Пізніше потрібно прибрати nickname. У схемі видаляємо поле:
model User {
id Int @id @default(autoincrement())
email String @unique
}Потім створюємо нову міграцію:
npx prisma migrate dev --name remove-user-nicknamePrisma створить нову міграцію, яка видалить поле з бази даних.
Це не видалення старої міграції. Історія залишається послідовною:
add-user-nickname
remove-user-nicknameТакий підхід особливо важливий, якщо попередня міграція вже застосована на staging або production.
Якщо видалити застосовану міграцію з репозиторію, виникне розбіжність:
база даних знає про міграцію;
локальна папка prisma/migrations її більше не містить.
У результаті migrate status повідомить про проблему, а інші середовища можуть отримати непередбачувану структуру.
Застосовані міграції не слід редагувати або видаляти. Замість цього потрібно створювати нові міграції.
Якщо міграція не виконалася повністю, Prisma позначає її відповідним станом у таблиці _prisma_migrations.
Спочатку потрібно:
переглянути текст помилки;
перевірити стан бази;
визначити, чи були виконані окремі SQL-команди;
виправити причину помилки;
лише після цього продовжувати міграцію.
Для отримання інформації про стан можна виконати:
npx prisma migrate statusКоманда migrate resolve використовується для узгодження стану міграцій із фактичним станом бази. Наприклад:
npx prisma migrate resolve --rolled-back 20260901121500_add_postsЦе не скасовує SQL-зміни автоматично. Команда лише повідомляє Prisma, що невдалу міграцію слід вважати відкоченою. Перед використанням потрібно переконатися, що база справді перебуває у відповідному стані.
Позначити міграцію як застосовану можна так:
npx prisma migrate resolve --applied 20260901121500_add_postsЦей варіант також не виконує SQL-команди. Він використовується лише тоді, коли зміни вже були застосовані вручну або іншим контрольованим способом.
Перед змінами в production потрібно мати резервну копію бази та план відновлення.
Якщо потрібно скасувати функціональну зміну, зазвичай виконують такі кроки:
змінюють schema.prisma на потрібний стан;
створюють нову зворотну міграцію;
перевіряють SQL-файл міграції;
тестують її на копії або staging-базі;
застосовують через migrate deploy.
Наприклад:
npx prisma migrate dev --name revert-posts-changeПісля перевірки нова міграція потрапляє до репозиторію і застосовується в production:
npx prisma migrate deployНе кожну зміну можна безпечно відкотити. Видалення колонки або таблиці може призвести до втрати даних. У таких випадках спочатку потрібно зробити резервну копію або використати поетапний підхід:
перестати використовувати старе поле в коді;
перенести або зберегти потрібні дані;
лише потім видалити поле окремою міграцією.
Для локальної розробки можна повністю скинути базу і застосувати всі міграції з початку:
npx prisma migrate resetКоманда:
видаляє дані з бази;
створює структуру заново;
застосовує всі міграції;
може запустити seed-скрипт, якщо він налаштований.
Під час виконання Prisma попросить підтвердження. Усі локальні дані буде втрачено.
Не використовуйте migrate reset у staging або production.
db push і міграціїКоманда:
npx prisma db pushсинхронізує Prisma-схему з базою без створення файлів міграцій.
Вона може бути корисною для швидких прототипів, але для проєкту з контрольованою історією змін слід використовувати:
npx prisma migrate dev --name назва-зміниОсновна різниця:
db push змінює базу без версійної історії;
migrate dev створює та застосовує міграцію;
migrate deploy застосовує вже створені міграції на іншому середовищі.
Не слід чергувати db push і міграції в одному середовищі без розуміння наслідків. Так можна отримати розбіжність між історією міграцій і реальною структурою бази.
migrate dev у productionmigrate dev призначена для локальної розробки. У production використовуйте:
npx prisma migrate deployФайлу schema.prisma недостатньо для відтворення всієї історії змін. Каталог prisma/migrations також потрібно зберігати в системі контролю версій.
Якщо міграція вже була застосована, її редагування може призвести до різних результатів у різних базах. Для нової поведінки створюйте нову міграцію.
Видалення старого каталогу міграції порушує історію. Відкат оформлюється новою міграцією.
Зміна типу колонки, перейменування поля або видалення таблиці може спричинити втрату даних. Перед такими міграціями перевіряйте згенерований migration.sql.
DATABASE_URLМіграція застосовується до бази, вказаної в DATABASE_URL. Перед запуском команди перевірте середовище та адресу бази, особливо якщо використовуєте production-конфігурацію.
Prisma Migrate зберігає зміни структури бази у папці prisma/migrations.
Для локальної розробки використовується npx prisma migrate dev --name назва.
Для staging і production використовується npx prisma migrate deploy.
Стан міграцій можна перевірити командою npx prisma migrate status.
Prisma не створює автоматичні down-міграції.
Відкат застосованої зміни виконується через нову зворотну міграцію.
Застосовані міграції не слід видаляти або редагувати.
migrate reset призначена лише для локальної бази, оскільки видаляє дані.
Каталог prisma/migrations потрібно зберігати разом із кодом проєкту.