--- description: How to create and run database migrations --- # Database Migration Workflow Follow these steps to create and apply database migrations using Prisma. --- ## Step 1: Update Prisma Schema Edit `prisma/schema.prisma`: ```prisma model Course { id Int @id @default(autoincrement()) title Json // { th: "", en: "" } description Json price Decimal @db.Decimal(10, 2) is_free Boolean @default(false) have_certificate Boolean @default(false) status CourseStatus @default(DRAFT) thumbnail String? category_id Int category Category @relation(fields: [category_id], references: [id]) created_by Int creator User @relation(fields: [created_by], references: [id]) chapters Chapter[] instructors CourseInstructor[] enrollments Enrollment[] created_at DateTime @default(now()) updated_at DateTime @updatedAt deleted_at DateTime? is_deleted Boolean @default(false) @@index([category_id]) @@index([status]) @@index([is_deleted]) } ``` --- ## Step 2: Create Migration // turbo Run migration command: ```bash npx prisma migrate dev --name add_course_model ``` This will: 1. Generate SQL migration file 2. Apply migration to database 3. Regenerate Prisma Client --- ## Step 3: Review Migration File Check generated SQL in `prisma/migrations/`: ```sql -- CreateTable CREATE TABLE "Course" ( "id" SERIAL NOT NULL, "title" JSONB NOT NULL, "description" JSONB NOT NULL, "price" DECIMAL(10,2) NOT NULL, "is_free" BOOLEAN NOT NULL DEFAULT false, ... CONSTRAINT "Course_pkey" PRIMARY KEY ("id") ); -- CreateIndex CREATE INDEX "Course_category_id_idx" ON "Course"("category_id"); ``` --- ## Step 4: Update Prisma Client // turbo Regenerate client if needed: ```bash npx prisma generate ``` --- ## Step 5: Create Seed Data (Optional) Update `prisma/seed.js`: ```javascript const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); async function main() { // Create categories const category = await prisma.category.create({ data: { name: { th: 'การเขียนโปรแกรม', en: 'Programming' }, description: { th: 'หลักสูตรด้านการเขียนโปรแกรม', en: 'Programming courses' } } }); // Create test user const user = await prisma.user.create({ data: { username: 'instructor1', email: 'instructor@example.com', password: '$2b$10$...', // hashed password role_id: 2 // INSTRUCTOR } }); // Create test course const course = await prisma.course.create({ data: { title: { th: 'Python สำหรับผู้เริ่มต้น', en: 'Python for Beginners' }, description: { th: 'เรียนรู้ Python', en: 'Learn Python' }, price: 990, is_free: false, category_id: category.id, created_by: user.id } }); console.log('Seed data created:', { category, user, course }); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); }); ``` --- ## Step 6: Run Seed // turbo Seed the database: ```bash npx prisma db seed ``` --- ## Common Migration Tasks ### Add New Field ```prisma model Course { // ... existing fields slug String @unique // New field } ``` // turbo ```bash npx prisma migrate dev --name add_course_slug ``` ### Add Index ```prisma model Course { // ... existing fields @@index([created_at]) // New index } ``` ### Add Relation ```prisma model Lesson { // ... existing fields quiz_id Int? quiz Quiz? @relation(fields: [quiz_id], references: [id]) } ``` ### Rename Field ```prisma model Course { // Old: instructor_id created_by Int // New name } ``` **Note**: Prisma will detect rename and ask for confirmation --- ## Production Migration ### Step 1: Generate Migration (Dev) ```bash npx prisma migrate dev --name migration_name ``` ### Step 2: Commit Migration Files ```bash git add prisma/migrations/ git commit -m "Add migration: migration_name" ``` ### Step 3: Deploy to Production ```bash npx prisma migrate deploy ``` **Important**: Never use `migrate dev` in production! --- ## Rollback Migration ### Option 1: Manual Rollback ```bash # Find migration to rollback ls prisma/migrations/ # Manually run the down migration (if exists) psql $DATABASE_URL < prisma/migrations/XXXXXX_migration_name/down.sql ``` ### Option 2: Reset Database (Dev Only) ```bash npx prisma migrate reset ``` **Warning**: This will delete all data! --- ## Troubleshooting ### Migration Failed ```bash # Check database status npx prisma migrate status # Resolve migration npx prisma migrate resolve --applied MIGRATION_NAME # or npx prisma migrate resolve --rolled-back MIGRATION_NAME ``` ### Schema Drift ```bash # Check for drift npx prisma migrate diff # Reset and reapply npx prisma migrate reset ``` ### Generate Client Error ```bash # Clear node_modules and reinstall rm -rf node_modules npm install # Regenerate client npx prisma generate ``` --- ## Checklist - [ ] Schema updated in `prisma/schema.prisma` - [ ] Migration created with descriptive name - [ ] Migration SQL reviewed - [ ] Migration applied successfully - [ ] Prisma Client regenerated - [ ] Seed data updated (if needed) - [ ] Tests updated for new schema - [ ] Migration files committed to git --- ## Best Practices 1. **Descriptive Names**: Use clear migration names - ✅ `add_course_certificate_field` - ❌ `update_schema` 2. **Small Migrations**: One logical change per migration 3. **Review SQL**: Always check generated SQL before applying 4. **Test First**: Test migrations on dev database first 5. **Backup**: Backup production database before migrating 6. **Indexes**: Add indexes for frequently queried fields 7. **Constraints**: Use database constraints for data integrity