Skip to main content
Concordia uses Drizzle ORM for type-safe database migrations. Migrations are automatically generated from schema changes and can be applied to development or production databases.

Migration System Overview

The migration system uses:
  • Drizzle Kit: CLI tool for generating migrations from schema files
  • PostgreSQL: Target database (local or production)
  • TypeScript: Migration scripts with type safety
  • Version Control: Migration history tracked in __drizzle_migrations table

Configuration Files

The project has separate configuration files for development and production:

Development Config

Production Config

The production config uses a glob pattern to load all schema files, while development uses a single export file.

Environment Variables

Set these in your .env file:

Generating Migrations

Basic Generation

After modifying schema files, generate a migration:
This command:
  1. Scans schema files in src/database/schemas/
  2. Compares with the current database state
  3. Generates SQL migration files
  4. Updates the migration journal

Generation Process

The generation script (scripts/db/db.generate.ts) automatically:
  • Validates schema files - Ensures all schema files exist and are not empty
  • Checks for missing imports - Prompts to add unamported schema files to schemas.ts
  • Creates migration directory - Auto-creates src/database/migrations/meta/ if needed
  • Initializes journal - Creates _journal.json if it doesn’t exist
  • Detects new migrations - Shows which migration files were created

Interactive Import Management

If you add new schema files, the generator will prompt you:
Enter the numbers of schemas to import, separated by commas.

Production Generation

To generate migrations for production:
Production generation compares against the production database. Make sure you’re connected to the correct database!

Migration Files

Migrations are stored in src/database/migrations/:

Migration File Format

Each migration is a .sql file with SQL statements:

Migration Journal

The _journal.json file tracks migration history:

Running Migrations

Apply Pending Migrations

Run all pending migrations:
The migration script (scripts/db/db.migrate.ts):
  1. Connects to the database
  2. Creates __drizzle_migrations table if needed
  3. Checks which migrations have been applied
  4. Runs pending migrations in order
  5. Records each migration in the tracking table

Migration Output

Production Migrations

To run migrations on production:
You’ll be prompted for confirmation:
Or set CONFIRM_PROD=oui to skip the prompt:

No Pending Migrations

If all migrations are already applied:

Migration Tracking

Migrations are tracked in the __drizzle_migrations table:
Query applied migrations:

Database Reset (Development)

To completely reset the database and rerun all migrations:
This will DROP ALL TABLES in the database. Only use this in development!
The reset process:
  1. Prompts for confirmation
  2. Drops all tables in the public schema
  3. Clears the migration history
  4. Reruns all migrations from scratch

Migration Best Practices

1. Always Generate Before Migrating

2. Version Control

Commit migration files to git:

3. Never Modify Applied Migrations

Once a migration has been applied (especially in production), never modify it. Instead:
  1. Create a new migration to fix the issue
  2. Generate it with npm run db:generate
  3. Apply it with npm run db:migrate

4. Test Migrations Locally First

Always test migrations in development before production:

5. Handle Schema Changes Carefully

Safe - Add new nullable columns or columns with defaults:

6. Use Transactions

The migration runner automatically wraps each statement in a transaction:
  • If a migration fails, it rolls back
  • The migration is marked as failed
  • Fix the issue and rerun

7. Handle Duplicate Objects Gracefully

The migration system ignores duplicate object errors:
This allows reruns without breaking on existing objects.

Common Migration Scenarios

Adding a New Table

1

Create schema file

Create src/database/schemas/my_table.schema.ts:
2

Export from schemas.ts

Add to src/database/schemas.ts:
3

Generate migration

4

Apply migration

Modifying Existing Table

1

Edit schema file

Modify the schema definition in src/database/schemas/:
2

Generate migration

Review the generated SQL:
3

Apply migration

Adding Foreign Key

1

Update schema

2

Generate and apply

Data Migration

For complex migrations involving data transformation:
1

Generate schema migration

2

Edit SQL file

Open the generated migration file and add data transformation:
3

Apply migration

Troubleshooting

Migration Fails

If a migration fails:
  1. Check the error message - It will show which statement failed
  2. Fix the schema - Correct the schema definition
  3. Delete the failed migration - Remove the generated .sql file
  4. Regenerate - Run npm run db:generate again
  5. Reapply - Run npm run db:migrate

Schema Out of Sync

If your database schema doesn’t match the code:
For production, create corrective migrations instead.

Missing Migration Journal

If _journal.json is missing:

Schema File Not Found

If generation fails with “schema file not found”:
  1. Check src/database/schemas.ts exists
  2. Verify it exports all schema files
  3. Ensure schema files use correct imports

Production Migration Failed

If a production migration fails:
  1. Don’t panic - Migrations use transactions and roll back
  2. Check logs - Identify the failing statement
  3. Create fix migration - Generate a corrective migration
  4. Test locally - Apply fix to local database first
  5. Apply to production - Run fix migration on production

Next Steps

Schema Reference

View complete database schema documentation

Relationships

Learn about table relationships and foreign keys