All projects
Developer toolsIn progress2026

migrail

A linter that reads your database migrations the way Postgres will run them, and tells you what will lock before you merge.

Source code
The migrail wordmark above the tagline catch dangerous migrations before they reach production, with a sample MR101 error finding
Rules shipped in v0.1
25
PostgreSQL versions lock-verified
12 to 18
Migration tools detected, no config
9
First commit to the v0.1 release
1 day

About the project

migrail catches the migrations that take production down: an index built without CONCURRENTLY, a foreign key added without NOT VALID, a type change that rewrites a 50 GB table under an exclusive lock. Every finding names the lock mode, what it blocks, why Postgres does it, and the fix. v0.1 ships 25 rules for PostgreSQL 12 to 18 and reads nine migration tools with no config file, and every lock claim in it is verified against real databases in CI. The end goal is a checker that speaks your framework, reads your application code before you drop a column, and estimates real impact from real table sizes. Free, Apache-2.0, no account.

The problem

Teams take production down with migrations that read fine in review. CREATE INDEX without CONCURRENTLY holds a lock that blocks every insert, update and delete until the index finishes building. A column rename breaks the pods still serving traffic on the old code during a rolling deploy. A type change rewrites a 50 GB table while holding an exclusive lock.

None of that is visible in the diff. It is visible in the PostgreSQL locking documentation, and code review is not the moment anyone opens it.

What it does

migrail parses every migration with the same parser PostgreSQL uses and reports what the database will do with it. Each finding names the lock mode, the operations it blocks, why Postgres behaves that way, and the fix as a statement you can paste:

CREATE INDEX CONCURRENTLY idx_orders_created_at ON orders (created_at);

It runs with no arguments and no config file. It finds the migrations directory, detects which tool wrote it, works out the git base branch, and checks only what changed on your branch.

migrail check reporting that CREATE INDEX blocks writes on the orders table, with the concurrent fix underneathmigrail check reporting that CREATE INDEX blocks writes on the orders table, with the concurrent fix underneath

Testing the lock claims

A linter that is wrong about a lock is worse than no linter. Tell someone a safe statement is dangerous and they learn to ignore you. Tell them a dangerous one is safe and you caused the outage.

So every lock mode and rewrite claim in migrail is verified against real databases. The harness starts PostgreSQL 12 through 18 in Docker, runs each statement, reads back the locks the server actually took, and compares them with what the model predicted. A disagreement fails the build. make lockverify runs it locally and CI runs it nightly.

Where it is now

v0.1 is released. It covers PostgreSQL 12 to 18 with 25 rules across locks, table rewrites, transaction mistakes, code compatibility and data loss. It reads golang-migrate, goose, Atlas, Flyway, Prisma, Drizzle, dbmate, sqitch and plain SQL directories, including each tool’s own conventions for transaction mode.

Output is a compiler-style diagnostic with a code frame, or JSON for anything that needs to read it. It installs as a single binary through Homebrew or a checksum-verified script, on macOS, Linux and Windows for amd64 and arm64. Every release publishes checksums, a cosign signature and an SBOM.

migrail detecting a goose migration and reporting that CREATE INDEX CONCURRENTLY cannot run inside a transactionmigrail detecting a goose migration and reporting that CREATE INDEX CONCURRENTLY cannot run inside a transaction

Where it is going

Most of what separates migrail from a Postgres SQL linter is still ahead of it.

v0.2 adds native adapters for Django, Alembic, Rails, Laravel, EF Core, Knex, TypeORM, Sequelize and Liquibase, plus a capture mode that supports any other tool by running its migration command against a throwaway database and reading the SQL it emits. Fixes then arrive in your framework’s syntax. Rails users get disable_ddl_transaction! and algorithm: :concurrently. Django users get AddIndexConcurrently and atomic = False.

v0.3 reads your application code. Before you drop or rename a column, migrail searches your Go, Python, Ruby, TypeScript, PHP, Java and C# for the queries and models that still use it, so it can tell you whether the migration is safe to ship ahead of the code change. With a read-only connection to staging it also estimates impact from real table sizes, for example that a rewrite on a 41 million row table will hold its exclusive lock for roughly four to nine minutes.

v1.0 is the full PostgreSQL catalogue with stable rule IDs and schemas. MySQL and MariaDB follow in v2, then SQL Server, SQLite and CockroachDB.

Why it stays free

Atlas moved its Postgres lock checks behind a login and a paid tier. squawk is free and good, and its own documentation says it has no special support for Django or any other ORM. strong_migrations is excellent and Rails only.

The checks that stop you breaking production should not be the paid tier. In migrail they never will be: Apache-2.0, no account, no config file, no feature gating in the CLI or in CI.

Need something like this built?

Send me the details, or book a 15 minute call from the contact page.

Start a conversation
Previous projectTwynsaScan your face, meet the people who look like you.Next projectArclineA freight forwarding website built around one promise: you always know where your cargo is.
Package
migrail
Role
Design, engineering and releases
Year
2026

Stack

  • Golang
  • PostgreSQL
  • Docker
rayanstudio

Full-stack engineer building web and mobile apps from Buea, Cameroon.

  • Home
  • Projects
  • Articles
  • Contact
  • Privacy
console.log("Made with passion")
rayan.json
{
  "developer": "Chiatiah Rayan",
  "stack": [
    "React",
    "Next.js",
    "TypeScript",
    "Tailwind",
    "Node",
    "Golang"
  ],
  "status": "Always learning",
  "coffee": true,
  "bugs": 0, // (hopefully)
  "uptime": "99.99%",
  "lastDeployed": "October 26th, 2026"
}
© 2026 Chiatiah Rayan Nguea. All rights reserved.
Built withusingNext.js&Tailwind CSS