Keel

Docs / Database / Migrations

Migrations

Schema changes go through bun run db:generate then bun run db:migrate, not db:push.

Why not db:push

drizzle-kit push diffs your schema against the live database and applies the result directly, no SQL file, no history. Against a Supabase-hosted Postgres it crashes introspecting CHECK constraints on system schemas (auth, storage, extensions) with an unrelated TypeError, regardless of the schemaFilter in drizzle.config.ts. db:generate + db:migrate avoid touching those schemas at all, generate only ever reads public (per schemaFilter: ["public"]), and migrate just replays SQL.

The normal path

bash
bun run db:generate   # writes lib/db/migrations/NNNN_name.sql + meta/NNNN_snapshot.json
bun run db:migrate    # applies pending migrations to DATABASE_URL

db:generate diffs your schema files against the last snapshot and writes a plain SQL migration plus a metadata snapshot Drizzle uses for the next diff. db:migrate applies whatever hasn't run yet, tracked in a __drizzle_migrations table it creates on first run.

drizzle-kit generate needs a TTY

When a schema diff is ambiguous, renaming a column, or sometimes just adding one, generate prompts interactively to resolve it. That prompt doesn't work in a non-interactive shell (CI, some AI coding assistants' sandboxed shells), and it fails outright rather than guessing.

If generate won't run non-interactively

Hand-write the migration instead of fighting the prompt:

  1. Write the migration SQL yourself, a plain ALTER TABLE/CREATE TABLE statement matching what you changed in the schema file.
  2. Generate the matching meta/NNNN_snapshot.json programmatically, via drizzle-kit/api's generateDrizzleJson, not freehand. The snapshot has to reflect the exact post-migration schema shape for the next db:generate to diff against correctly.
  3. Add an entry to lib/db/migrations/meta/_journal.json matching the existing entries' shape.
  4. Run bun run db:migrate as normal, it replays SQL, it doesn't care whether the file was generated or hand-written.

This is the same workaround used throughout Keel's own build (billing column renames, a plain column add, several new columns at once), it's about the hand-written snapshot's shape in general, not just rename ambiguity.

Edit this page on GitHub →Last updated Jul 22, 2026