Schema diffing & migration generation

Read this page in the documentation

Schema diffing & migration generation SchemaDiffer compares your model definitions against the schema the database actually has, and MigrationGenerator turns that diff into up / down SQL. Together they answer "what has drifted?" and "what would fix it?" — without applying anything, so you can read the statements before they run. This is the reviewable middle ground between sync({ alter: true }), which changes the database immediately, and writing every migration by hand. Diffing Call | Returns | --- | --- | diffModel(Model) | A SchemaDiff for one model. | diffAll() | One SchemaDiff per registered model. | getColumnChanges(...) | Column-level changes only. | getIndexChanges(...) | Index-level changes only. | getConstraintChanges(...) | Constraint-level changes only. | getForeignKeyChanges(...) | Foreign-key changes only. | A SchemaDiff is: Every change carries a type of create (in the model, not in the database), modify (in both but different) or delete (in the database, not in the model). Options Option | Default | Effect | --- | --- | --- | compareIndexes | on | Include index differences. | compareConstraints | on | Include constraint differences. | compareForeignKeys | on | Include foreign-key differences. | serializeColumnType | dialect default | Override how a DataType is rendered for comparison. | skipColumnProperties | [] | Column properties to ignore when comparing. | skipColumnProperties is the pressure valve for cosmetic drift. Databases normalise things — a VARCHAR(255) may report a collation you never asked for, a default may come back quoted differently — and without it the differ reports a modify on every run. Add the noisy property once you have confirmed it is noise. Generating migrations up is emitted in order — columns, then indexes, then constraints, then foreign keys — and down is that list reversed, so a rollback undoes the work in the opposite order to how it was applied. generateDown: false leaves down empty. generateAllMigrations(diffs) maps the whole set in one call. Option | Default | Effect | --- | --- | --- | namePrefix | generator default | Leading segment of the migration name. | generateDown | — | Produce rollback statements. | includeComments | — | Prepend -- Migration: <table> and a timestamp. | dialectOptions | — | Passed through to the dialect. | Writing the migration to a file The generator produces statements, not files. Combining it with the migration layout is a few lines: Reading a diff before you trust it Generated migrations are a starting point, not an answer. Three things to check every time: A delete on a column is a data loss. The differ cannot know whether the column is gone on purpose or the model is simply out of date. A rename looks like a delete plus a create. Nothing in the diff carries the intent that name became fullname; applied as generated, that drops the data. Write renames by hand. A modify on a type may not be safe. Narrowing VARCHAR(255) to VARCHAR(50) compiles fine and fails, or truncates, on real rows. How it compares to sync({ alter: true }) | sync({ alter: true }) | SchemaDiffer + MigrationGenerator | --- | --- | --- | Applies changes | immediately | never — you decide | Rollback | none | generated down | Reviewable | no | yes — plain SQL strings | Drops columns | only with { drop: true } | reports them; you choose | Good for | local development | staging and production change management | Related reading Migrations — running and tracking migrations QueryInterface — the API migrations are written against Indexes & constraints Defining models