Skip to main content
ShipFree uses Drizzle ORM for database management and migrations. This guide covers how to generate, run, and manage database migrations in development and production.

Overview

Drizzle migrations are:
  • Type-safe: Generated from your TypeScript schema
  • Automatic: SQL is generated for you
  • Version-controlled: Migration files are committed to Git
  • Reversible: Can be rolled back if needed

Migration Commands

ShipFree provides three migration commands in package.json:
package.json

Command Breakdown

Drizzle Configuration

Migrations are configured in drizzle.config.ts:
drizzle.config.ts
Configuration details:
  • schema: Location of your database schema definition
  • out: Directory where migration files are generated
  • dialect: Database type (PostgreSQL)
  • dbCredentials.url: Database connection string

Migration Workflow

1. Update Database Schema

Edit your schema in src/database/schema.ts:
src/database/schema.ts

2. Generate Migration

Generate SQL migration files from your schema changes:
Output:
This creates a new file in the migrations/ directory with the SQL needed to apply your schema changes.

3. Review Generated Migration

Check the generated SQL file:
migrations/0001_new_posts_table.sql

4. Run Migration Locally

Apply migrations to your local database:
Output:

Migration Script

The migration script is located at scripts/migrate.ts:
scripts/migrate.ts
How it works:
  1. Loads environment variables from .env
  2. Selects database URL based on NODE_ENV
  3. Connects to the database
  4. Runs all pending migrations from ./migrations folder
  5. Closes the connection

Environment Variables

Local Development

Set in .env:
.env

Production

Set in .env or environment:
.env
Important: Never commit production credentials to Git!

Production Migrations

Run migrations from your local machine against the production database:
Output:

Option 2: CI/CD Pipeline

Run migrations in your CI/CD workflow:
.github/workflows/deploy.yml

Option 3: Vercel Post-Deploy Hook

Run migrations after Vercel deployment using a deploy hook:
  1. Add a migrate script to package.json:
  1. Set up environment variables in Vercel:
  1. Create an API route for migrations (protected):
src/app/api/migrate/route.ts

Best Practices

1. Always Review Generated Migrations

Before running migrations, review the generated SQL:

2. Test Migrations Locally First

Always test on local database before production:

3. Backup Production Database

Before running production migrations:

4. Run Migrations in Maintenance Window

For large schema changes:
  • Schedule a maintenance window
  • Put application in maintenance mode
  • Run migrations
  • Verify data integrity
  • Restore application

5. Use Transactions

Drizzle automatically wraps migrations in transactions, so failed migrations are rolled back automatically.

6. Version Control Migrations

Always commit migration files to Git:

Troubleshooting

Migration Fails with “DATABASE_URL is not set”

Solution: Set the appropriate environment variable:

Migration Fails with Connection Error

Check database connectivity:
Common issues:
  • Incorrect connection string
  • Database server not running
  • Firewall blocking connection
  • SSL/TLS requirements (add ?sslmode=require to connection string)

Migration Already Applied

Drizzle tracks applied migrations in the database. If you try to run the same migration twice, it will skip it:

Rollback a Migration

Drizzle doesn’t have built-in rollback. To undo a migration:
  1. Option A: Write a new migration to reverse changes
  2. Option B: Restore from database backup
  3. Option C: Manually write SQL to undo changes

Advanced Usage

Custom Migration Files

You can create custom SQL migrations:
migrations/0010_custom_indexes.sql

Migration Naming

Drizzle generates migration names based on:
  • Sequence number (0001, 0002, etc.)
  • Description from schema changes
Example: 0001_create_users_table.sql

Next Steps

Resources