Skip to content

Detect schema drift between the stored snapshot and the live database #32

Description

@kimjbstar

The problem

The previous state comes from a JSON snapshot this tool wrote into SequelizeMetaMigrations, not from the database. There is no introspection of the live schema anywhere in the diff path.

That works as long as this tool is the only thing that changes the schema. When something else does — a hand-written ALTER TABLE, a manually edited migration, an old sync({ alter: true }), a restore from a backup with different migration history, or another tool in the mix — the snapshot and the database drift apart, and nothing notices.

Why it matters

The failure is silent. Nothing errors, nothing warns; the next generated migration is simply wrong.

  • A column added outside the tool is absent from the snapshot, so the next run emits addColumn for it and the migration fails with "column already exists".
  • A column dropped outside the tool stays in the snapshot, so every subsequent diff is computed on a false premise.
  • Worst case: an unknown column is missing from a changeColumn that redefines the table around it.

What detection would look like

makeMigration
  → describeTable() the tables in the snapshot
  → compare against the stored snapshot
  → on a mismatch: report what differs, and stop (or warn, per option)

Prisma catches this by replaying migration history into a shadow database. Drizzle Kit uses the same snapshot approach as this tool and has the same blind spot.

Why it is not a small change

describeTable() returns what the database stored, which is a different representation from the snapshot:

  • Sequelize.STRING(255) vs VARCHAR(255), and the spelling differs per dialect
  • Sequelize.BOOLEAN vs MySQL's TINYINT(1)
  • a false default coming back as "0" (observed in this repo's sqlite integration tests)

A useful comparison needs a per-dialect type normalization layer. Done carelessly it produces false positives on every run, which is worse than no check at all.

A smaller first step

Comparing only existence — tables and column names, no type comparison — catches most of the scenarios above with almost no false-positive risk. That may be worth shipping on its own before attempting type-level comparison.

Notes

  • Documented as a known limitation in the README under "Limitations".
  • Should be opt-out at minimum; the extra describeTable() calls cost a round trip per table.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions