Why Remote Migrations?
The RDS instance is configured with:- Public Access: Disabled
- Security Group: Allows inbound PostgreSQL (5432) only from Lambda security group
- VPC: Private subnets (no internet gateway route)
Quick Start
From the project root:scripts/migrate-remote.sh, which sends Prisma migration SQL to the Worker Lambda’s run-sql action.
Migration Pipeline
Themigrate-remote.sh script performs the following steps:
1. Discover Migration Files
Prisma migrations are stored inpackages/api/prisma/migrations/ with timestamp-prefixed directories:
2. Send SQL to Worker Lambda
For each migration file, the script:- Reads
migration.sql - Builds a JSON payload with the
run-sqlaction - Invokes the Worker Lambda
- Parses the response for success/failure
packages/api/src/worker.ts):
3. Handle Already-Applied Migrations
If a migration was already applied (e.g., table already exists), Prisma throws an error:4. Update Migration Tracking Table
Prisma maintains a_prisma_migrations table to track which migrations have been applied:
prisma migrate deploy and prisma migrate status recognize the migrations as applied.
Creating New Migrations
Migrations are created during local development:1. Modify Prisma Schema
Editpackages/api/prisma/schema.prisma:
2. Generate Migration
Run Prisma’s migration tool against your local PostgreSQL database:migration.sql):
3. Commit Migration
Commit the migration file to git:4. Deploy to Remote Database
Run the remote migration script:Deployment Order
When schema changes are deployed:Schema vs. Migrations vs. Seed
| File | Purpose | When to Edit |
|---|---|---|
schema.prisma | Source of truth for DB schema | When adding/modifying models |
migrations/*/migration.sql | SQL statements to apply schema changes | Never edit manually (generated by prisma migrate dev) |
seed.ts | Initial data (admin user, sample prompts) | When adding default data |
Local Development Workflow
Local development uses a separate PostgreSQL database (not the remote RDS):1. Set Up Local Database
Create a local PostgreSQL database:2. Configure .env
Create packages/api/.env:
3. Apply Migrations
Apply all migrations to the local database:4. Seed Database
Populate the local database with sample data:packages/api/prisma/seed.ts):
Troubleshooting
Migration fails with “relation already exists”
Cause: Migration was already applied (the tracking table is out of sync) Solution: The script automatically skips these. If the migration truly needs to run, drop the table manually viarun-sql:
pnpm migrate:remote.
DATABASE_URL not set
Cause: The CloudFormation template is missing the DATABASE_URL environment variable on the Worker Lambda
Solution: Verify the CloudFormation template has:
Prisma Client out of sync with schema
Cause: Schema was modified but Prisma Client was not regenerated Solution: Regenerate Prisma Client:.prisma/client with the latest schema.
Migration timeout (Lambda times out after 120s)
Cause: Migration SQL is too large or slow Solution: Increase--cli-read-timeout in migrate-remote.sh:
Direct SQL Execution (Advanced)
For ad-hoc SQL queries or schema inspection, you can invoke the Worker Lambda directly:$executeRawUnsafe does not return query results, only the number of rows affected. Use Prisma Studio or a SQL client for inspecting data.
Prisma Studio (Local Only)
Prisma Studio provides a GUI for browsing and editing database data:Rollback Migrations
Prisma does not support automatic rollback. To rollback a migration:1. Create a New Migration
Write the inverse SQL manually:migration.sql:
2. Apply the Rollback Migration
Best Practices
- Never edit
migration.sqlmanually — Always useprisma migrate devto generate migrations - Test migrations locally first — Run against local PostgreSQL before deploying to RDS
- One migration per feature — Keep migrations small and focused
- Commit migrations to git — Migrations are part of the codebase, not infrastructure
- Run migrations before deploying API — Ensure schema is up-to-date before code expects new tables
- Avoid destructive migrations — Drop tables only when absolutely necessary (backup first)
Migration Safety
- RDS Backups: 7-day retention (automated)
- Snapshot on Deletion: RDS stack has
DeletionPolicy: Snapshot(production) - Test Environment: Always test migrations in dev/staging before production
- Idempotent Migrations: Use
IF NOT EXISTS,IF EXISTSwhere possible - Transaction Wrapping: Each migration runs in a transaction (automatic rollback on failure)
Schema Management Tools
| Tool | Command | Purpose |
|---|---|---|
prisma migrate dev | npx prisma migrate dev --name <name> | Create new migration (local dev) |
prisma migrate deploy | npx prisma migrate deploy | Apply pending migrations (local only) |
pnpm migrate:remote | bash scripts/migrate-remote.sh | Apply migrations to remote RDS |
prisma migrate status | npx prisma migrate status | Check migration status |
prisma generate | npx prisma generate | Regenerate Prisma Client |
prisma studio | npx prisma studio | GUI database browser (local only) |
prisma db push | npx prisma db push | Prototype schema changes (skip migrations) |