Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

migguard 🛡️

Catch database migration conflicts before the merge, not after the database is broken.

migguard is a fast, zero-database-connection CLI and CI merge gatekeeper that detects branching migration conflicts across Django, Alembic, Prisma, Rails, and Knex.

npm version License: MIT CI


The Problem

On any team with two or more developers, two people create migrations on separate feature branches. The branches merge into main.

  • In Django/Alembic, the migration graph now has two heads.
  • In Prisma/Rails/Knex, timestamps are out-of-order or duplicate.

Nobody finds out until someone runs the migration in staging or production—when the database schema enters an inconsistent state. Existing ORM CLIs only catch this after you've already merged and attempted to migrate.

migguard catches conflicts before the merge in pre-commit and CI.


Supported Frameworks

Framework Engine Detection Mechanism Resolution Command
Django Engine A (DAG) Per-app leaf node detection (dependencies / run_before) python manage.py makemigrations --merge
Alembic Engine A (DAG) Multi-head DAG detection (revision / down_revision) alembic merge heads
Prisma Engine B (Timestamp) Folder timestamp ordering vs git merge-base npx prisma migrate resolve
Rails Engine B (Timestamp) 14-digit timestamp filenames & schema.rb merge conflicts rails db:migrate:status
Knex Engine B (Timestamp) Lexicographical timestamp sorting vs git merge-base Rename migration timestamp

Quick Start

Run directly via npx in any repository:

npx migguard

Or install as a dev dependency:

# npm
npm install -D migguard

# pnpm
pnpm add -D migguard

# yarn
yarn add -D migguard

Example Output

migguard · django · 2 apps · 34 migrations

✗ Conflict: multiple leaf nodes in app `payments` (2 unmerged migration heads)

    payments/migrations/0013_add_refund_status.py
    payments/migrations/0013_add_currency_field.py

  → python manage.py makemigrations --merge

1 conflict · 33 migrations OK · 0.2s

CI / GitHub Action

Add migguard to your GitHub pull request workflow to block broken migrations before they reach main:

# .github/workflows/migrations.yml
name: Migration Check

on:
  pull_request:
    branches: [main, master]

jobs:
  check-migrations:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Full history needed for merge-base detection

      - name: Run migguard
        uses: poorvith-mp/migguard@v0.1.0
        with:
          target: main

Pre-Commit Hook

Ensure developers never commit branching migration heads locally:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/poorvith-mp/migguard
    rev: v0.1.0
    hooks:
      - id: migguard
        files: (migrations/|db/migrate/|prisma/migrations/)

CLI Options & Flags

Usage: migguard [options]

Catch database migration conflicts before the merge, not after the database is broken.

Options:
  -V, --version            output the version number
  -t, --target <branch>    Explicit comparison target branch for timestamp-based ORMs (default: upstream or main)
  -f, --framework <name>   Skip detection and force a specific framework (django, alembic, prisma, rails, knex)
  --json                   Output results in JSON format for automation
  --strict                 Treat warnings as failures (exit code 1)
  -q, --quiet              Only print conflicts, suppress warnings and clean statuses
  -h, --help               display help for command

Exit Codes

Code Meaning
0 Clean: All migrations linear, no conflicts found.
1 Conflict: Branching heads or out-of-order timestamps detected.
2 Warning: Detection uncertain / unparseable file (promoted to 1 with --strict).

Core Architecture

migguard uses a two-engine design tailored to how ORMs manage migrations:

1. Engine A: DAG Traversal (Django & Alembic)

Migration files contain explicit parent pointers (dependencies in Django, down_revision in Alembic). migguard builds the dependency graph directly from source files and identifies leaf nodes. Multiple leaves = multiple unmerged heads.

  • Handles Alembic down_revision tuple merge points without false positives.
  • Handles Django squashed migrations (replaces) cleanly.
  • Checks django-linear-migrations max_migration.txt fast path.

2. Engine B: Timestamp vs Merge Base (Prisma, Rails, Knex)

Migration files contain no parent pointers; ordering is implied by filename timestamps. migguard identifies the git merge-base with your target branch and compares files added on each side to detect collisions or out-of-order execution before merge.


Hard Security & Privacy Guarantees

  • 🛡️ Zero Database Connection: migguard inspects files and git history only. No database credentials in CI.
  • 🔒 Zero Code Execution: Python and Ruby files are parsed textually and structurally. No eval(), no subprocess execution of repo code.
  • No Telemetry / Offline: Zero external network calls.
  • 🛑 Read-Only: migguard never modifies or rewrites your migration files.

License

MIT © Poorvith M P

About

Catch database migration conflicts before the merge, not after the database is broken. Multi-framework CLI for Django, Alembic, Prisma, Rails, & Knex.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages