How does Drizzle handle schema migrations?
How does Drizzle handle schema migrations?
About drizzle-team/drizzle-orm · 2 messages · last activity 1 Oct 2026
Based on what's retrievable from this repository's changelogs and the RepoPilot import-graph signals, Drizzle's migration story is split across two packages with distinct responsibilities:
1. drizzle-kit — schema diffing and migration file generation
drizzle-kit is the CLI tool responsible for comparing your TypeScript schema against the database (or a prior snapshot) and producing SQL migration files / DDL statements. Several commands are documented in the changelogs:
drizzle-kit generate— the implicit workflow shown throughout the changelogs: you declare tables withpgTable/mysqlTable/etc. (e.g. withcheck()constraints, views, materialized views), and drizzle-kit serializes that schema intoCREATE TABLE/CREATE VIEW/CREATE MATERIALIZED VIEWSQL statements [changelogs/drizzle-kit/0.26.0.md:L50-L107].drizzle-kit export— a newer command (introduced in 0.30.1) that outputs the schema's SQL DDL directly to the console (via--sql) rather than writing migration files, specifically to ease interop with other migration tools like Atlas [changelogs/drizzle-kit/0.30.1.md:L3-L35].drizzle-kit push— referenced as a limitation case: for certain changes (like altering a view's SQL definition),pushrequires a manual two-step dance of commenting out the view, pushing, then restoring it with the new definition and pushing again, whereasgeneratehandles such changes automatically [changelogs/drizzle-kit/0.26.0.md:L95-L107].- Dialect-specific migration strategies — drizzle-kit distinguishes dialects explicitly in config (e.g.
dialect: "turso"vsdialect: "sqlite"), because Turso/libsql evolved separate migration strategies starting around 0.25.0, and using themigratefunction requires a minimum@libsql/clientversion [changelogs/drizzle-kit/0.25.0.md:L1-L51]. casingconfiguration — bothdrizzle-orm(at the connection level, e.g.drizzle('node-postgres', { connection, casing: 'snake_case' })) anddrizzle-kit(viadefineConfig({ casing: 'snake_case' })) need matching casing config so that generated migrations and runtime queries agree on how camelCase TS fields map to snake_case DB columns [changelogs/drizzle-kit/0.25.0.md:L146-L180].- Checks, views, and RLS/Supabase roles are all first-class citizens in the schema that generate/push account for — e.g.
check()constraints render asCONSTRAINT ... CHECK (...)[changelogs/drizzle-kit/0.26.0.md:L3-L38], and Supabase-specific predefined roles/tables (declared.existing()) are treated by drizzle-kit purely as external references for FK/policy purposes, not as entities it tries to manage itself [changelogs/drizzle-kit/0.27.0.md:L312-L416].
2. drizzle-orm — applying migrations at runtime
The actual "run these SQL migration files against my live connection" step lives in a per-driver migrate function, historically imported from a dedicated submodule rather than bundled into the main connector, e.g. import { migrate } from 'drizzle-orm-pg/node/migrate' [changelogs/drizzle-orm-pg/0.14.0.md:L1-L9] and import { migrate } from 'drizzle-orm-sqlite/better-sqlite3/migrate' [changelogs/drizzle-orm-sqlite/0.14.1.md:L1-L9]. That same 0.14.0 release also replaced the old Connector class pattern (new PgConnector(client).connect()) with the now-familiar drizzle(client) factory function.
On the architecture side, RepoPilot's import graph flags a direct circular dependency specifically in this migration pathway: `drizzle-kit/src/cli/commands/migrate.ts -> drizzle-kit/src/migrationPreparator.ts -> drizzle-kit/src/serializer/index.ts -> drizzle-kit/src/cli/views.ts -> drizzle-kit/src/utils.ts -> drizzle
Did this answer what you came for?
Want to ask your own question?
Open chat for drizzle-team/drizzle-ormPublic Q&A. Generated by RepoPilot from the actual source of drizzle-team/drizzle-orm. AI answers can be incomplete or stale — verify before relying on them.