Database Migrations
Manage database schema changes with Prisma Migrate: creating, applying, and troubleshooting migrations.
Migrations track and apply schema changes to your database in a controlled, version-controlled way. Prisma Migrate generates SQL migration files by comparing your schema with the last known state, giving you full visibility into what changes before it hits the database.
This guide is part of the Database Configuration documentation.
Migration Workflow
The typical workflow is:
- Edit the schema in
packages/database/src/prisma/schema.prisma - Create and apply a migration:
pnpm --filter @kit/database prisma:migrate - Review the generated SQL file in
packages/database/src/prisma/migrations/*/migration.sql - Regenerate the client if needed:
pnpm --filter @kit/database prisma:generate
prisma migrate dev creates AND applies
prisma:migrate runs prisma migrate dev, which generates the SQL migration and applies it to your development database in one step. There is no separate generate + migrate two-step. Review the generated SQL afterward, especially for destructive changes like dropping columns or changing types.
Repo Conventions
Keep examples aligned with the current schema style in this repo:
- ids are explicit
String @id - ownership fields use camelCase such as
organizationId - table names are controlled with
@@map - migrations live in
packages/database/src/prisma/migrations
Adding a New Table
Add the model to packages/database/src/prisma/schema.prisma:
packages/database/src/prisma/schema.prisma
model Project { id String @id name String organizationId String createdAt DateTime @default(now()) organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) @@index([organizationId]) @@map("project")}Add the reverse relation on Organization:
model Organization { // existing fields... projects Project[]}Create and apply the migration:
pnpm --filter @kit/database prisma:migratePrisma writes a SQL file such as:
-- CreateTableCREATE TABLE "project" ( "id" TEXT NOT NULL, "name" TEXT NOT NULL, "organizationId" TEXT NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "project_pkey" PRIMARY KEY ("id"));-- CreateIndexCREATE INDEX "project_organizationId_idx" ON "project"("organizationId");-- AddForeignKeyALTER TABLE "project" ADD CONSTRAINT "project_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;Adding a Column
Add the new field to your existing model:
model Project { id String @id name String description String? // New nullable column organizationId String}Create and apply:
pnpm --filter @kit/database prisma:migrateThe generated SQL:
ALTER TABLE "project" ADD COLUMN "description" TEXT;Adding required columns to populated tables
Adding a required (non-nullable) column to a table that already has rows fails without a default. Either give the field a @default(...), or add it as nullable first, backfill data, then make it required in a follow-up migration.
Changing Column Types
Be careful with type changes. Some are safe, some are not:
Safe changes:
- Making a column nullable
InttoBigInt
Unsafe changes (may fail or lose data):
StringtoInt- Making a column required when NULLs exist
- Reducing precision
For unsafe changes, edit the generated migration.sql to add a backfill step before applying, or write the data migration in a separate step.
Migration Files
Migrations are stored in packages/database/src/prisma/migrations:
packages/database/src/prisma/migrations/├── 20260115235605_init/│ └── migration.sql├── 20260305073325/│ └── migration.sql├── 20260413023018/│ └── migration.sql├── 20260629091122/│ └── migration.sql└── migration_lock.tomlEach migration is a timestamped directory containing a single migration.sql. Prisma records applied migrations in the _prisma_migrations table in your database and applies only the ones that haven't run yet.
Production Deployments
Use prisma migrate deploy in CI and production — not prisma migrate dev. migrate deploy applies pending migrations without prompting or generating new ones:
# In your deployment script or CI/CD pipelineDATABASE_URL="$PROD_DATABASE_URL" pnpm --filter @kit/database exec prisma migrate deployDeployment Best Practices
- Test migrations on staging first: Always run migrations against a staging database before production
- Backup before migrating: Take a database backup before applying migrations to production
- Run migrations before deploying code: The new code may depend on schema changes
- Keep migrations small: Smaller migrations are easier to debug and roll back
Resetting in Development
To wipe and rebuild your local database from scratch, re-applying every migration:
pnpm --filter @kit/database prisma:reset# or from the rootpnpm run db:resetReset drops all data
prisma:reset runs prisma migrate reset, which drops the database and re-applies all migrations. Never run it against a database with data you care about.
Rolling Back
Prisma Migrate does not have built-in rollback. For rollbacks:
- Write a reverse migration manually with
prisma migrate dev --create-only, then edit the SQL - Or restore from a database backup
- Or use your database provider's point-in-time recovery
For important changes, test migrations on a staging database first.
Common Mistakes to Avoid
Editing old migration files: Once a migration has been applied to any database (including staging), don't edit or delete it. Prisma tracks applied migrations by name and checksum.
Forgetting to commit migrations: Migration files in src/prisma/migrations must be committed to version control. They are the source of truth for your schema history.
Using prisma db push in production: prisma:push applies schema changes directly without creating migration files. Use it only for rapid prototyping in development. In production, always use proper migrations.
Adding required columns to populated tables without a backfill plan: Changing a column to required fails if NULLs exist. Write a data migration first, then change the constraint.
Frequently Asked Questions
What does prisma:migrate do?
How do I apply migrations in production?
How do I roll back a migration?
Can I edit generated migration SQL files?
Next: Client →