| name | wasp-database |
| description | Complete database migration workflow and schema management for Wasp projects. Use when modifying schema.prisma, running migrations, or working with database models. Includes MANDATORY restart requirement and PostgreSQL setup. |
| triggers | ["migration","schema change","database","prisma","migrate","schema.prisma","database model","postgres","db migrate","entity","wasp db"] |
| version | 1 |
| last_updated | "2025-10-18T00:00:00.000Z" |
| allowed_tools | ["Edit","Bash","Read"] |
Wasp Database Migration Skill
Quick Reference
When to use this skill:
- Modifying database schema
- Adding/changing models or fields
- Running migrations
- Database setup and configuration
- Schema errors or type mismatches
Key concepts:
- ALWAYS use
wasp db migrate-dev (NEVER prisma migrate dev)
- MANDATORY restart after migration for types to update
- PostgreSQL required for enums and PgBoss jobs
- Migration files are immutable (never edit/delete)
Critical Rules
NEVER use: npx prisma migrate dev (WRONG)
ALWAYS use: wasp db migrate-dev (CORRECT)
MANDATORY: Restart ../scripts/safe-start.sh after migration (multi-worktree safe, types regenerate)
NO exceptions: Even "simple" changes require restart - types will be stale without it
Complete Migration Workflow
Step 1: Edit schema.prisma
Location: app/schema.prisma
Common schema patterns:
// Primary key with auto-increment
model Task {
id Int @id @default(autoincrement())
description String
isDone Boolean @default(false)
createdAt DateTime @default(now())
// Relations
user User @relation(fields: [userId], references: [id])
userId Int
}
// Optional fields (add ?)
model User {
id Int @id @default(autoincrement())
email String? @unique // Optional
username String @unique // Required
}
// Enums (requires PostgreSQL)
enum TaskStatus {
TODO
IN_PROGRESS
DONE
}
model Task {
status TaskStatus @default(TODO)
}
// Unique constraints
model User {
email String @unique
@@unique([organizationId, username]) // Composite unique
}
Common field types:
String - Text
Int - Integer
Boolean - True/false
DateTime - Timestamp
Json - JSON data
String? - Optional string
- Add
@unique for unique constraint
- Add
@default(...) for default value
Step 2: Run Migration
wasp db migrate-dev --name "Descriptive migration name"
Examples of good migration names:
- ✅ "Add email to User"
- ✅ "Create Task model"
- ✅ "Add status field to Task"
- ✅ "Add unique constraint to username"
- ❌ "Update" (too vague)
- ❌ "Changes" (not descriptive)
- ❌ "Migration" (meaningless)
What this command does:
- Generates SQL migration file in
app/migrations/
- Applies migration to database
- Updates Prisma client
- DOES NOT regenerate Wasp types (requires restart!)
Command output:
Applying migration `20251018120000_add_email_to_user`
✓ Generated Prisma Client to ./node_modules/@prisma/client
Step 3: RESTART Wasp (MANDATORY)
../scripts/safe-start.sh
Why restart is MANDATORY:
- Wasp types only regenerate on restart
- TypeScript won't see new fields without restart
- NO exceptions - ALWAYS restart after migration
- Even for "small" changes like adding one field
Common error if you skip restart:
Property 'email' does not exist on type 'User'
Fix: Stop wasp (Ctrl+C) and run ../scripts/safe-start.sh (multi-worktree safe)
Step 4: Verify Types Updated
Check that new fields appear in TypeScript imports:
import type { Task } from "wasp/entities";
const task: Task = {
id: 1,
description: "Test",
status: "TODO",
createdAt: new Date(),
};
If fields still missing:
- Confirm migration ran successfully
- Verify you restarted wasp
- Check for TypeScript cache issues:
wasp clean && ../scripts/safe-start.sh
Database Configuration
schema.prisma Structure
Required structure:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql" // or "sqlite" for development
url = env("DATABASE_URL") // ✅ MUST use env()
}
// Your models below
model User {
id Int @id @default(autoincrement())
}
Critical rules:
- ✅ Use
env("DATABASE_URL") for database URL
- ❌ NEVER hardcode database URLs
- ✅ Keep schema.prisma in
app/schema.prisma
- ❌ DO NOT configure database in main.wasp
PostgreSQL vs SQLite
PostgreSQL (Production & Recommended):
- ✅ Supports Prisma enums
- ✅ Supports PgBoss (background jobs)
- ✅ Production-ready
- ✅ Better performance
- ❌ Requires PostgreSQL server
SQLite (Development Only):
- ✅ No setup required
- ✅ Quick for prototyping
- ❌ NO enum support
- ❌ NO PgBoss support
- ❌ Limited concurrent writes
Recommendation: Use PostgreSQL from the start if you need enums or jobs.
Switch from SQLite to PostgreSQL:
// Before (SQLite)
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// After (PostgreSQL)
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Then update .env.server:
DATABASE_URL="postgresql://username:password@localhost:5432/myapp_dev"
Common Migration Errors
Error: "Cannot find module 'wasp/entities'"
Cause: Forgot to restart wasp after migration
Fix:
../scripts/safe-start.sh
Error: "Property 'newField' does not exist on type 'User'"
Cause: Types not regenerated (forgot restart)
Fix: Restart ../scripts/safe-start.sh (multi-worktree safe)
Verification:
import type { User } from "wasp/entities";
Error: "Migration failed: relation already exists"
Cause: Database out of sync with migrations
Fix (Development only!):
wasp db reset
wasp db migrate-dev "Fresh start"
../scripts/safe-start.sh
Production fix: Never use db reset in production. Contact database admin.
Error: "Enum types are not supported by sqlite"
Cause: Using enums with SQLite
Fix: Switch to PostgreSQL:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Update .env.server:
DATABASE_URL="postgresql://localhost:5432/myapp_dev"
Error: "Environment variable not found: DATABASE_URL"
Cause: Missing .env.server file
Fix: Create app/.env.server:
DATABASE_URL="postgresql://localhost:5432/myapp_dev"
Best Practices
✅ DO:
- Use descriptive migration names
- Commit migration files to git
- Restart immediately after migration
- Use
wasp db migrate-dev command
- Use
env("DATABASE_URL") in schema.prisma
- Test migrations in development first
- Keep schema.prisma in app root
❌ NEVER:
- Delete migration files (breaks history)
- Edit existing migrations (create new one instead)
- Use
prisma migrate dev directly
- Skip restart after migration
- Hardcode database URLs
- Force migrations in production
- Use
wasp db reset in production
Migration Workflow Examples
Example 1: Add Field to Existing Model
Scenario: Add email field to User model
Step 1: Edit schema.prisma
// Before
model User {
id Int @id @default(autoincrement())
}
// After
model User {
id Int @id @default(autoincrement())
email String? @unique
}
Step 2: Run migration
wasp db migrate-dev "Add email to User"
Step 3: Restart wasp
../scripts/safe-start.sh
Step 4: Verify in code
import type { User } from "wasp/entities";
Example 2: Create New Model
Scenario: Create Task model with relations
Step 1: Edit schema.prisma
model Task {
id Int @id @default(autoincrement())
description String
isDone Boolean @default(false)
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
userId Int
}
model User {
id Int @id @default(autoincrement())
tasks Task[] // Add back-relation
}
Step 2: Run migration
wasp db migrate-dev "Create Task model"
Step 3: Restart wasp
Example 3: Add Relation Between Models
Scenario: Add User-Task relation
Step 1: Edit schema.prisma
model User {
id Int @id @default(autoincrement())
tasks Task[] // Add this line
}
model Task {
id Int @id @default(autoincrement())
description String
user User @relation(fields: [userId], references: [id])
userId Int
}
Step 2: Run migration
wasp db migrate-dev "Add User-Task relation"
Step 3: Restart wasp
Example 4: Add Enum (PostgreSQL only)
Scenario: Add TaskStatus enum
Step 1: Verify PostgreSQL
datasource db {
provider = "postgresql" // Required for enums
}
Step 2: Add enum to schema.prisma
enum TaskStatus {
TODO
IN_PROGRESS
DONE
}
model Task {
id Int @id @default(autoincrement())
status TaskStatus @default(TODO)
}
Step 3: Run migration
wasp db migrate-dev "Add TaskStatus enum"
Step 4: Restart wasp
Step 5: Use in code
import type { TaskStatus } from "wasp/entities";
import { TaskStatus } from "@prisma/client";
const status: TaskStatus = TaskStatus.TODO;
PostgreSQL Setup
Local Development (macOS)
brew install postgresql
brew services start postgresql
createdb myapp_dev
Local Development (Linux)
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib
sudo service postgresql start
sudo -u postgres createdb myapp_dev
.env.server Configuration
Create/update: app/.env.server
DATABASE_URL="postgresql://username:password@localhost:5432/myapp_dev"
Format breakdown:
postgresql:// - Protocol
username:password - Database credentials
localhost:5432 - Host and port
myapp_dev - Database name
Example for local development:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/myapp_dev"
Docker Alternative
Start PostgreSQL in Docker:
docker run --name postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
-d postgres
Create database:
docker exec -it postgres psql -U postgres -c "CREATE DATABASE myapp_dev;"
.env.server:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/myapp_dev"
Troubleshooting
Database connection failed
Check 1: PostgreSQL running
pg_isready
Check 2: DATABASE_URL in .env.server
cat app/.env.server
Check 3: Database exists
psql $DATABASE_URL -c "SELECT 1;"
Migrations out of sync
Development only - reset database:
wasp db reset
wasp db migrate-dev "Fresh start"
../scripts/safe-start.sh
Production - manual sync:
- Never use
db reset
- Contact database admin
- Apply migrations manually if needed
Types not showing new fields
Always the same fix: Restart ../scripts/safe-start.sh (multi-worktree safe)
If still broken:
wasp clean
../scripts/safe-start.sh
Enum not working
Check 1: PostgreSQL?
datasource db {
provider = "postgresql" // NOT sqlite
}
Check 2: Import values correctly?
import { TaskStatus } from "@prisma/client";
const status = TaskStatus.TODO;
import type { TaskStatus } from "wasp/entities";
const status: TaskStatus = "TODO";
import { TaskStatus } from "wasp/entities";
Quick Checklist
Migration workflow:
Database setup:
After changes:
Critical Commands
wasp db migrate-dev "Description"
wasp db reset
wasp db studio
wasp db migrate status
References
Complete guide:
docs/TROUBLESHOOTING-GUIDE.md (Database Issues section)
.tmp/extraction/wave1-agent-a-cursor-rules.md (Migration workflow)
Related skills:
wasp-operations - For using entities in operations
tdd-workflow - For testing database changes
External docs: