Migration Convention
This page mirrors
docs/src/app/docs/database-schema/migration-convention.md. Keep both files aligned to avoid conflicting guidance.
Purpose
Defines mandatory rules for creating, reviewing, and deploying Prisma migrations in StudyBoost shared environments.
Core Principles
- Forward-fix only on shared environments. Never rewrite migration history after merge.
- Safety must be enforceable, not implicit. Destructive changes require explicit checklist + approval.
- Intent must be documented in the migration itself. Reviewers should understand why/impact without searching old PRs.
- Parallel work is allowed, unsafe ordering is not. Coordinate and resolve ordering conflicts without manually editing
_prisma_migrations.
Required Migration Header (Mandatory)
Every migration.sql must start with this intent block:
-- ============================================================
-- StudyBoost — <Short Title>
-- Migration: YYYYMMDDHHmm_short_description
-- Date: YYYY-MM-DD HH:mm
-- PURPOSE: <why this migration exists>
-- IMPACT: <tables/columns/indexes and runtime impact>
-- DATA RISK: <none|low|medium|high + brief justification>
-- ROLLBACK STRATEGY: <forward-fix plan, not migrate down>
-- Safe to re-run: uses IF NOT EXISTS / IF EXISTS guards
-- ============================================================
Dangerous Migration Classification (Mandatory)
A migration is dangerous if it does any of the following:
DROP TABLE,DROP COLUMN, or destructiveALTERon critical columns.- Large backfills/data rewrites that can lock tables or alter many rows.
- Constraint tightening that may fail on existing data.
For dangerous migrations:
- Include
-- Type: Dangerous migrationin header. - Include a dedicated section in SQL comments:
-- DANGEROUS CHANGE REVIEW. - PR description must include checklist evidence (backup, row counts, approvals).
Destructive Migration Checklist (Required for Prod/Staging)
Before running pnpm run migrate:prod for any dangerous migration, all must be confirmed:
- Backup/snapshot confirmed (timestamp + owner recorded in PR).
- Pre-migration row counts captured for affected tables.
- Expected data impact documented (what will be removed/changed).
- Explicit approver sign-off recorded in PR (backend owner or designated reviewer).
- Post-migration verification queries prepared and run.
No checklist evidence = no deploy.
Parallel Migration Workflow (Scalable)
- Coordinate with teammates if migrations touch overlapping tables.
- Multiple migration PRs may be open in parallel.
- Before merge, rebase on latest
devand regenerate migration if ordering drift occurs. - If conflict occurs, never manually edit
_prisma_migrations. Instead:- Recreate migration from clean state in correct order.
- Re-run
pnpm run migrate:status. - Document resolution in PR.
Migration Changelog Requirement (Human-Readable)
Each migration PR must include a short rationale block:
- Problem solved
- Why this approach was chosen
- Data-impact summary
- Operational notes (runtime/locking expectations)
This is required for explainability and onboarding.
Quick Reference
Current active Neon branch (v2)
- Shared v2 migration work is currently targeting Neon branch
br-blue-glade-a4t2qrmy:https://console.neon.tech/app/projects/frosty-haze-02246987/branches/br-blue-glade-a4t2qrmy/tables?database=StudyboostDatabase - When running shared migration commands, confirm
backend/.envDATABASE_URLpoints to this v2 branch.
Commands (Shared DB Development)
- Shared DB status check:
pnpm run migrate:status - Shared DB apply pending migrations:
pnpm run migrate:prod - Optional alias (non-destructive):
pnpm run migrate(mapped tomigrate:status) - Do not use
migrate:devon the shared Neon branch.
When we finally switch to production (Runbook)
- Final production apply command:
pnpm -C backend run migrate:prod - Recommended safety sequence at release time:
pnpm -C backend run migrate:statuspnpm -C backend run migrate:prodpnpm -C backend run migrate:status
If target DB is a non-empty branch copy (P3005)
- Symptom:
migrate:prodfails withP3005(The database schema is not empty). - Cause: branch has existing tables/data but no Prisma migration history for that branch yet.
- One-time baseline flow before deploy:
pnpm -C backend run migrate:statuspnpm -C backend prisma migrate resolve --applied 000000000000_baselinepnpm -C backend run migrate:statuspnpm -C backend run migrate:prodpnpm -C backend run migrate:status
- Note:
migrate resolve --appliedupdates migration history only; it does not delete table rows.
What developers should run in dev (shared branch model)
- For day-to-day development on the shared Neon DB:
pnpm -C backend run migrate:statuspnpm -C backend run migrate:prodpnpm -C backend run migrate:status
- Team rule: treat the shared dev DB like a deploy target; use
migrate:prodfor applying migration files. - Use
migrate:devonly on disposable local databases.
Command Safety Note (Required Team Habit)
- Always run explicit scripts with a colon (
migrate:status,migrate:prod,migrate:dev). - Do not use
pnpm run migrate statusexpectingmigrate:status; this runs themigratescript with an extra argument. - Use
pnpm run migrate:statusfor status checks andpnpm run migrate:prodonly when you intentionally want to apply migrations.
Rollback / Recovery Policy
- Prisma does not provide a standard
migrate downworkflow in normal team usage. - If a migration is wrong on shared dev/staging/prod, create a new forward corrective migration (do not rewrite history).
prisma migrate resetis destructive (data loss) and is last resort only for disposable local environments.- For shared environments, never use reset; run
pnpm run migrate:statusto verify state before and after corrective migrations.
Example Header
-- ============================================================
-- StudyBoost — Add User Preferences Table
-- Migration: 202604211430_add_user_preferences
-- Date: 2026-04-21 14:30
-- PURPOSE: Persist per-user UI preferences for dashboard experience.
-- IMPACT: Adds new `user_preferences` table and PK index; no destructive operations.
-- DATA RISK: low (additive schema only).
-- ROLLBACK STRATEGY: forward-fix by follow-up migration if schema adjustments are needed.
-- Safe to re-run: uses IF NOT EXISTS guards
-- ============================================================
CREATE TABLE IF NOT EXISTS user_preferences (
user_id UUID PRIMARY KEY,
theme VARCHAR(50) NOT NULL DEFAULT 'light'
);