Skip to main content
Database migrations allow you to version control schema changes and safely apply them across environments. CharleOS uses Drizzle Kit for automatic migration generation.

Migration Files

Migrations are stored in the drizzle/ directory:
Each migration file contains raw SQL that transforms the database schema.

Development Workflow

Local Development (Fast Iteration)

For rapid development, use db:push to sync schema directly:
1

Edit Schema

Modify lib/db/schema.ts to add/change tables or columns
2

Push Changes

Instantly applies changes to your local dev database (no migration file created)
3

Test Changes

Verify schema changes in Drizzle Studio
db:push is perfect for local development but doesn’t create migration files. It directly syncs your schema to the database.

Production Workflow (Safe Deployment)

For production, always generate migration files:
1

Edit Schema

Make your changes to lib/db/schema.ts
2

Generate Migration

Creates a new SQL file in drizzle/XXXX_name.sql
3

Review Generated SQL

Always review the SQL to ensure it does what you expect
4

Test Locally

Apply the migration to your local database:
5

Commit Changes

6

Deploy

Push to GitHub. Migrations run automatically on Vercel deployment.

Common Migration Examples

Adding a Column

Schema change:
Generated migration:

Adding a New Table

Schema change:
Generated migration:

Adding a Foreign Key

Schema change:
Generated migration:

Renaming a Column

Schema change:
Generated migration:

Dropping a Column

Schema change:
Generated migration:
Destructive changes like dropping columns or tables are irreversible. Always back up data before deploying destructive migrations.

Migration Commands

Handling Destructive Changes Safely

Approach 1: Multi-Step Migration

Instead of dropping a column directly, use a multi-step approach: Step 1: Make column nullable
Step 2: Migrate data to new column
Step 3: Drop old column (separate deployment)

Approach 2: Feature Flags

Use feature flags to gradually roll out schema changes:
  1. Add new column (deploy)
  2. Update app to use new column (behind flag)
  3. Enable flag and migrate data
  4. Remove old column (new deployment)

Migration Conflicts

Resolving Conflicts

If multiple developers create migrations simultaneously:
1

Pull Latest Changes

2

Check for Conflicts

Look for conflicts in drizzle/meta/_journal.json
3

Resolve Journal Conflicts

The journal tracks all migrations. Manually merge the arrays:
4

Regenerate Your Migration

This creates a new migration that accounts for both changes
5

Test Locally

Apply both migrations locally to ensure they work together

Rolling Back Migrations

Drizzle doesn’t have built-in rollback. Options:

Option 1: Create Reverse Migration

Manually write SQL to undo the change:

Option 2: Restore from Backup

For critical failures, restore from Neon backup:
  1. Go to Neon Console → Your Branch → Backups
  2. Select point-in-time before migration
  3. Restore to a new branch
  4. Test and switch production

Option 3: Fix Forward

Create a new migration that fixes the problem:

Seeding Data

Use seed scripts for initial configuration data:
Example seed script:

Best Practices

Keep migrations focused and atomic:✅ Good:
  • 0048_add_task_tags.sql - Adds tags table and task_tag junction
❌ Bad:
  • 0048_massive_refactor.sql - Adds tags, renames 5 columns, drops 3 tables
Don’t blindly trust auto-generated migrations:
Always apply migrations to local dev database before deploying:
Once a migration is deployed to production:
  • Never edit the SQL file
  • Create a new migration to fix issues
  • Editing applied migrations breaks migration history
Drizzle doesn’t auto-create indexes on foreign keys. Add manually:
In commit messages and PR descriptions:

Troubleshooting

Migration Failed to Apply

Error: “relation ‘task’ does not exist” Fix:
  1. Check if you’re on the correct database branch
  2. Verify all previous migrations are applied
  3. Check drizzle/meta/_journal.json for missing entries

Schema Out of Sync

Error: “Schema drift detected” Fix:

Duplicate Migration

Error: “Migration 0048 already exists” Fix:

CI/CD Integration

Migrations run automatically on Vercel deployments via postinstall script:
This ensures migrations are applied before the app starts.

Database Overview

Database architecture and tools

Schema

Complete schema reference

Drizzle ORM

Query builder syntax

Deployment

How migrations run in production