Catch the MySQL migration that locks your table — before it merges
Presift reads the .sql migrations in a pull request and flags two things
that take sites down: destructive changes that cannot be rolled back, and
ALTER TABLE operations that copy or rebuild the table or block writes.
Each finding arrives as an annotation on the changed line, with the rule, the reason and the MySQL
manual reference — so the decision happens in review, not at 2 a.m.
- Reads
.sqlmigrations: plain SQL, Flyway, Liquibase formatted SQL, and the SQL emitted by Prisma Migrate, Drizzle Kit, goose, dbmate and golang-migrate - Rules follow the MySQL 8.0 online-DDL operations matrix and cite it in every finding
- GitHub Action; text, JSON and SARIF 2.1.0 output; pull-request annotations
- No database connection and no schema access: the analysis runs on your own runner
Who it is for
Teams that keep MySQL schema changes as .sql files in the repository and merge them
through GitHub pull requests — where nobody is formally the DBA, and the person reviewing the
migration is the person who wrote it. Presift is the second reader that always shows up: it knows
which statement classes rebuild or block, and it says so on the diff.
Today that means GitHub Actions on Linux x86_64 runners with Python 3.9+. Other CI systems and platforms are not supported yet.
What it catches
| Rule | Statement class | Read more |
|---|---|---|
| MG001 destructive-change | DROP TABLE, TRUNCATE, DROP COLUMN, dropping partitions | Destructive schema changes |
| MG002 blocking-or-rebuilding-alter | charset/collation conversion, data-type changes, primary-key changes, ADD FOREIGN KEY, STORED generated columns, FULLTEXT/SPATIAL indexes, partitioning, ENGINE=/ROW_FORMAT=/FORCE | ALTER TABLE locking and rebuilds, charset conversion, primary keys |
| MG003 missing-algorithm-lock-assertion | a risky ALTER with no ALGORITHM=/LOCK= clause | Why assert ALGORITHM and LOCK |
| MG004 add-column-position-not-instant | ADD COLUMN … FIRST/AFTER before 8.0.29 | ADD COLUMN FIRST / AFTER |
Four rules, deliberately. Each one is tied to a statement class the manual documents as rebuilding, blocking or irreversible — not to style preferences.
What a finding looks like
✖ MG002 ERROR db/migrations/V12__charset.sql:3
ALTER TABLE users: CONVERT TO CHARACTER SET rebuilds the table and blocks concurrent DML
Why: Converting a table's character set rewrites every row (the manual lists it as in place,
rebuilds table, permits concurrent DML: No); writes are blocked for the duration.
Do: Avoid on large/busy tables during traffic. Options: expand/contract; gh-ost /
pt-online-schema-change; or a maintenance window. Assert the expectation explicitly with
ALGORITHM=... so MySQL fails fast if it cannot comply.
Ref: https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html
Intentional changes are silenced in the migration itself, with a reason the next reviewer can read:
-- presift: allow MG001 replaced by orders_v2 in migration 0141.
Evaluate it on your own migrations — 30 days, whole product, no key to copy
Add the Action to a pull-request workflow and give the job id-token: write. On its first
run the client asks GitHub for the job's own identity token and exchanges it, in memory, for a
short-lived evaluation entitlement. There is no form, no account, no card and nothing to paste.
name: migration-safety
on: [pull_request]
permissions:
contents: read
id-token: write # lets Presift start your 30-day evaluation
jobs:
presift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nishu-sde/presift@v1
with:
paths: db/migrations
fail-on: error
One 30-day evaluation per GitHub owner — an organisation or a personal account.
Linux x86_64 runners with Python 3.9+ (GitHub-hosted ubuntu-* runners qualify). Fork pull
requests cannot evaluate, because GitHub issues them no identity token. Outside GitHub Actions the
evaluation is not available; a paid organisation key is.
Where your SQL goes: nowhere
The analysis is a local process on your runner. The only request the client makes is to the release service, and it sends exactly four things: your key, the client version, the platform and the requested channel or pinned version. It never sends SQL, file names, findings or repository content. There is no telemetry and no usage reporting. The downloaded engine is verified against a signature and digest before it is allowed to run.
What Presift does not do
It does not guarantee zero downtime, and a clean run does not mean a migration is safe. Presift sees
the statement, not your database: not the current schema, table size, MySQL version,
foreign_key_checks, replication or traffic. Where the outcome depends on the existing column
definition or the server version, the finding says so and is marked medium confidence. It does not read
Liquibase XML/YAML, framework DSL migrations (Laravel, Rails, Django, TypeORM), PostgreSQL or SQL
Server. If you need schema-as-code, drift detection or approval workflows, Presift is not that tool.
What it costs
The 30-day evaluation is free and complete. After it, continued use needs an annual organisation licence — intended at $290 per organisation per year. That is an initial pricing hypothesis — subject to validation: there is no checkout, no payment processor connected, no licence issued and no customer yet. Pricing detail.