Create database migrations using Drizzle Kit. Use when adding/modifying tables, columns, or indexes. Ensures schema.ts and migrations stay in sync.
Create schema changes with proper migrations.
ALWAYS use drizzle-kit generate to create migrations. NEVER write SQL migration files manually.
Why this matters:
drizzle/meta/drizzle-kit generate to fail with confusing prompts about tables being "created or renamed"If you're tempted to write SQL by hand (e.g., for data migrations), create a separate script in scripts/ instead.
src/lib/schema.tsdrizzle/*.sql (last 2-3)Edit src/lib/schema.ts with your changes:
pgTable()Run Drizzle Kit to generate migration SQL:
pnpm drizzle-kit generate
This creates a new file in drizzle/ like 0011_descriptive_name.sql.
Read the generated migration and verify:
WARNING: Only test migrations locally if POSTGRES_URL points to a LOCAL database.
If it points to production, skip this step - migrations will run automatically on Vercel deploy.
To check your database URL:
echo $POSTGRES_URL # Should be localhost or local container
If local database is configured:
pnpm build # Runs migrations automatically
pnpm cli stats # Verify queries work
IF NOT EXISTS clauses (signals potential drift)// schema.ts
export const myTable = pgTable('my_table', {
// existing columns...
newColumn: varchar('new_column', { length: 255 }),
});
export const myTable = pgTable('my_table', {
// columns...
}, (table) => [
index('idx_my_table_column').on(table.column),
]);
export const newTable = pgTable('new_table', {
id: serial('id').primaryKey(),
// columns...
}, (table) => [
// indexes...
]);
generate commands to fail. ALWAYS use drizzle-kit generate.IF NOT EXISTS or IF EXISTS - These clauses signal you're writing SQL by hand. Generated migrations never include them.drizzle-kit generateBefore committing:
pnpm build (only if local DB configured)IF NOT EXISTS clauses (clean migration)