Skip to main content

Framework-agnostic linter for database migration folders — catch duplicate version numbers, sequence gaps, and missing down-migrations before CI does. Zero dependencies.

Project description

migrolint

A framework-agnostic linter for your database migrations folder. It catches the boring, expensive mistakes that pass locally and only blow up when CI actually runs the migrations — duplicate version numbers, sequence gaps, and up migrations with no matching down. No database connection, no framework lock-in, zero dependencies (pure standard library).

pip install migrolint

migrolint                      # auto-detects ./migrations, db/migrations, ...
migrolint db/migrations --strict

The problem

Two developers branch off main, each adds 0007_add_index.sql, both merge. Now your migrations folder has two migrations claiming version 0007. Your runner picks one and silently skips the other — or aborts the whole deploy. This is a known, recurring failure in every sequence-numbered migration tool.

The existing linters (django-migration-linter, Flyway's own checks) are tied to one framework or need a live database. If you use raw SQL with goose, dbmate, golang-migrate, or a hand-rolled folder, there's nothing that just looks at the filenames and tells you they're sane. That's migrolint.

What it checks

Rule Severity Meaning
DUPE_NUM error two migrations share a version number (the merge-collision bug)
MISSING_DOWN warning an up migration has no matching down (only flagged if the project uses up/down splits)
SEQ_GAP warning a hole in an integer sequence — usually a deleted or un-merged migration
BAD_FORMAT warning a file whose name no known convention recognizes

Naming conventions it understands

migrolint reads version numbers out of the filename, across the conventions people actually use:

Convention Example
Flyway V1__init.sql, U1__undo.sql, R__refresh.sql, V1.1__patch.sql
golang-migrate / dbmate 0001_create_users.up.sql + 0001_create_users.down.sql
goose / Rails 20230101120000_create_users.sql (timestamp prefix)
minimalist 1_init.sql, 2-add-index.sql

Timestamp-style versions are recognized but exempt from SEQ_GAP (they're not meant to be contiguous). Well-known non-migration files (schema.rb, structure.sql, seeds.rb, …) and any non-migration extension are skipped.

Usage

migrolint                      # scan the first migrations dir it finds
migrolint db/migrations        # scan a specific dir
migrolint app/migrations svc/migrations   # scan several
migrolint --json               # machine-readable, for tooling
migrolint --strict             # warnings become errors (exit 1) — good for CI
migrolint --ext .sql,.py       # override which extensions count
migrolint --ignore baseline.sql,seed.sql

You can also run it as a module: python -m migrolint db/migrations.

As a pre-commit / CI gate

# .pre-commit-config.yaml
- repo: local
  hooks:
    - id: migrolint
      name: migrolint
      entry: migrolint --strict
      language: system
      pass_filenames: false
# GitHub Actions
- run: pipx run migrolint --strict

Example output

migrolint db/migrations (14 files, 12 migrations)

  ✗ DUPE_NUM     version 0007 used by 2 migrations:
       0007_add_index.up.sql
       0007_add_orders_fk.up.sql
  ⚠ MISSING_DOWN 0009_drop_legacy.up.sql — no matching .down file
  ⚠ SEQ_GAP      missing version(s): 5

1 error, 2 warnings.

Exit codes

Code Meaning
0 clean (or only warnings, without --strict)
1 errors found — or warnings, when --strict is set
2 usage / IO error (no migrations dir, unreadable path)

Also available for Node

Same checks, same flags: npx migrolint (source: migrolint). Both ports read filenames identically, so a mixed-language team gets the same verdict.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

migrolint-0.1.0.tar.gz (11.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

migrolint-0.1.0-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file migrolint-0.1.0.tar.gz.

File metadata

  • Download URL: migrolint-0.1.0.tar.gz
  • Upload date:
  • Size: 11.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for migrolint-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2f9219829e8107170f416022f50f3c3e6a5afcf9c3b4d238642ce4eb2d2d0852
MD5 c035dc9f6307a58198c7734b42acf4cc
BLAKE2b-256 17d5d4651e2cb85207e3fe78c8f0b31dbd698cfc52f4fa008362b52511dd90dc

See more details on using hashes here.

File details

Details for the file migrolint-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: migrolint-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for migrolint-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8545a7badb58b204e547931848ce322b7b28c799fa48f4b48e557e9011f4da2d
MD5 4ac53caeb434ee17c9e635fc205a219a
BLAKE2b-256 5162dd053830d8564757395b9452fa59232fb3a0b612f6124e82ca56d7e6e177

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page