Getting Started
Database Drivers
Schema Integrations
Seed Generators
Utilities and Testing
The following files were used as context for generating this wiki page:
Migration Differ is a critical subsystem within drizzle-kit responsible for calculating the transition between two database schema snapshots. Its primary role is to ingest historical and current schema representations, perform a deep structural diff, and produce a deterministic sequence of DDL (Data Definition Language) operations required to synchronize a database instance with its defined schema code.
By abstracting the complexity of detecting additions, deletions, renames, and modifications across tables, columns, indexes, and constraints, the Migration Differ serves as the bridge between declarative schema definitions and imperative database migrations. It ensures that schema drift is captured accurately, supporting both standard migration file generation and "push" operations for direct schema synchronization.
Architecturally, the subsystem follows a multi-stage pipeline: ingestion of JSON-serialized schemas, resolution of name/schema changes via external input (e.g., user-provided renaming hints), execution of diff algorithms, and finally, transformation of those diffs into actionable JSON statement objects that generators (SQL generators) translate into executable SQL commands.
The core logic of schema comparison is handled via snapshotsDiffer.ts and jsonDiffer.js. When comparing two schemas, the differ does not merely perform a shallow key-value comparison; it reconciles differences by accounting for potential renames of tables, columns, and other database objects.
The snapshotsDiffer.ts file orchestrates this by invoking specialized resolvers for schemas, tables, and columns. The mechanism works by first identifying "raw" diffs using the json-diff library via the diffSchemasOrTables and diffColumns wrappers, and then patching the intermediate state (schemasPatchedSnap1) to ensure that rename resolutions are applied before the final diff is serialized into statement objects.
Sources: drizzle-kit/src/snapshotsDiffer.ts:15,603
The transformation pipeline converts structural differences into an ordered sequence of JsonStatement objects. The flow is as follows:
tablesResolver, columnsResolver, etc.) to determine if differences represent new entities, deleted entities, or renames.snapshotsDiffer maps the "previous" snapshot to the "new" snapshot's state, applying renames so that the subsequent diffing logic treats renames as continuity rather than a deletion/addition pair.applyJsonDiff iterates through the patched objects to produce a granular diff result.prepare...Json functions (e.g., preparePgCreateTableJson, prepareRenameColumns) which generate the specific JsonStatement primitives.fromJson function in the SQL generator consumes these statements to produce the final SQL string.Sources: drizzle-kit/src/snapshotsDiffer.ts:559-2131, drizzle-kit/src/jsonDiffer.js:90-411
Renames and moves are identified through a recursive mapping process. The differ uses helper functions like nameSchemaChangeFor to track how tables or schemas have migrated across logical boundaries.
Tip
The nameSchemaChangeFor function is crucial for preventing redundant "drop-then-create" operations. By resolving identity continuity before generating diffs, it ensures that changes inside a table or schema are preserved even if the container object is renamed or moved.
When a rename is detected, the differ updates the internal "snapshot" representation (e.g., schemasPatchedSnap1) before executing the final comparison logic. This ensures that the downstream diff algorithm views the renamed entity as existing in both states, albeit with a different identifier.
Sources: drizzle-kit/src/snapshotsDiffer.ts:519-538, drizzle-kit/src/snapshotsDiffer.ts:614-622
The applyPgSnapshotsDiff function (and its counterparts for other dialects) enforces a strict execution order of JsonStatement objects to minimize database errors. For example, indexes must generally be handled differently depending on whether the table is new or modified.
The order is dictated by the array manipulation logic in the later stages of the apply...SnapshotsDiff functions:
Caution
The ordering of statement application is sensitive. If drop-index operations are not performed before column alternations, the database may fail to execute column-level changes that are indexed. The code explicitly handles this by grouping and pushing specific arrays of statements in a specific sequence.
Sources: drizzle-kit/src/snapshotsDiffer.ts:1948-2023
A post-diff step cleanses the generated statements. Since the diffing logic is sometimes over-aggressive, the code includes a filtering stage where redundant or mutually exclusive operations are removed.
For example, when an operation involves both dropping a constraint and adding a new one, the filteredJsonStatements logic can remove operations that would result in invalid database states, such as alter_table_alter_column_drop_notnull followed by an identity operation change that is redundant.
// Example of redundant operation filtering
const filteredJsonStatements = jsonStatements.filter((st) => {
if (st.type === 'alter_table_alter_column_drop_notnull') {
if (jsonStatements.find((it) => it.type === 'alter_table_alter_column_drop_identity' ...)) {
return false;
}
}
// ...
});Sources: drizzle-kit/src/snapshotsDiffer.ts:2025-2051
libSqlPushUtilsIn scenarios where Drizzle is pushing changes to a Turso (LibSQL/SQLite) database, the libSqlPushUtils module provides utility methods to calculate actual data loss risks during table recreations. Since SQLite lacks support for many ALTER TABLE operations, the differ must often "recreate" tables by creating a new table and migrating the data.
The libSqlLogSuggestionsAndReturn function iterates over the generated statements and queries the existing database instance to check row counts, enabling the CLI to display warnings to the user if data deletion is imminent.
Sources: drizzle-kit/src/cli/commands/libSqlPushUtils.ts:113-355