DEV Community

Mickel Samuel
Mickel Samuel

Posted on • Originally published at migrationpilot.dev

Squawk vs MigrationPilot: PostgreSQL Migration Linters Compared

Squawk and MigrationPilot are both open-source PostgreSQL migration linters. Both analyze SQL files for dangerous operations and both integrate with CI. But they differ significantly in approach, rule depth, and what information they give you. This comparison is published on the MigrationPilot blog — take that into account and verify claims against the source code of both tools.

Quick Comparison

Feature Squawk MigrationPilot
Language Rust TypeScript
Safety rules 32 80 (77 free, 3 paid)
Lock type classification No Yes
Risk scoring No RED/YELLOW/GREEN
Auto-fix No 12 rules
GitHub Action Yes Yes (with PR comments)
VS Code extension Yes Yes
Config file .squawk.toml .migrationpilotrc.yml
Output formats Text, TSV, JSON CLI, JSON, SARIF, Markdown
Production context No Yes (paid, 3 rules)
Community ~1,000 stars, 600K downloads/mo New project
License Apache 2.0 MIT
Price Free (100%) Free (97% of rules), $19/mo for production context

Where Squawk Is Better

Let's start with where Squawk wins. Being honest about this matters more than marketing.

1. Speed

Squawk is written in Rust and is fast. For typical migration files (1-50 statements), both tools complete in under a second, so this doesn't matter in practice. But if you have very large migration files (thousands of statements), Squawk's Rust parser will be noticeably faster than MigrationPilot's TypeScript + WASM parser.

2. Maturity and community

Squawk has ~1,000 GitHub stars and ~600,000 downloads per month. It has been used in production by many teams for years. MigrationPilot is a new project with a small community. If you value battle-tested stability and want a tool that has already encountered and handled edge cases in the wild, Squawk has a significant advantage.

3. 100% free

Squawk is completely free with no paid tier. Every feature is available to everyone. MigrationPilot has 3 rules (out of 80) that require a $19/month subscription. While 97% of MigrationPilot's rules are free, Squawk's fully-free model is simpler and carries no risk of future paywall expansion.

Where MigrationPilot Is Better

1. Rule depth (80 vs 32)

MigrationPilot has 80 safety rules compared to Squawk's 32. The additional 48 rules cover:

  • Data safety: TRUNCATE TABLE, DROP CASCADE, unvalidated enum changes
  • Best practices: VARCHAR vs TEXT, TIMESTAMP vs TIMESTAMPTZ, missing IF NOT EXISTS
  • Lock safety: VACUUM FULL, LOCK TABLE, DISABLE TRIGGER, CLUSTER
  • Partition safety: partition key in PK, detach partition concurrently
  • Extension safety: PostGIS spatial indexes, pgvector HNSW vs IVFFlat
  • Transaction safety: uncommitted transactions, concurrent ops in transactions

The core rules overlap substantially — both tools catch CREATE INDEX without CONCURRENTLY, volatile defaults, and column type changes. The difference is in the long tail: patterns that are less common but equally dangerous when they occur.

2. Lock type classification

When MigrationPilot flags a dangerous statement, it tells you which lock the statement acquires. This is important because different locks have different impacts:

# MigrationPilot output
  MP001 [critical] CREATE INDEX without CONCURRENTLY
    Acquires: SHARE lock (blocks writes, allows reads)
    Table: orders
    Safe alternative:
      CREATE INDEX CONCURRENTLY idx_orders_customer ON orders (customer_id);

# Squawk output
migrations/001.sql:1:1: warning: prefer-create-index-concurrently
  Instead of `CREATE INDEX`, use `CREATE INDEX CONCURRENTLY`.
Enter fullscreen mode Exit fullscreen mode

Squawk tells you the operation is dangerous and suggests the fix. MigrationPilot also tells you the specific lock type (SHARE, ACCESS EXCLUSIVE, SHARE UPDATE EXCLUSIVE, etc.), which helps you understand the actual impact on running queries. A SHARE lock blocks writes but allows reads; an ACCESS EXCLUSIVE lock blocks everything.

3. Auto-fix

MigrationPilot can automatically fix 12 rule violations:

# Preview what would change
npx migrationpilot analyze migration.sql --fix --dry-run

# Apply fixes directly
npx migrationpilot analyze migration.sql --fix

# Example: MP001 auto-fix
# Before: CREATE INDEX idx_orders_customer ON orders (customer_id);
# After:  CREATE INDEX CONCURRENTLY idx_orders_customer ON orders (customer_id);
Enter fullscreen mode Exit fullscreen mode

Squawk does not have auto-fix. It reports the violation and links to documentation, but you make the change manually. For the 12 rules MigrationPilot can auto-fix, the fix is a deterministic text transformation — not a heuristic guess.

4. Risk scoring and prioritization

MigrationPilot assigns a risk score to each migration: RED (critical — likely to cause outage), YELLOW (warning — may cause issues), GREEN (safe). This helps teams with many migration files prioritize which ones to fix first.

Squawk reports violations with severity levels but does not provide an aggregate risk score for the migration as a whole.

5. Multiple output formats

MigrationPilot outputs in four formats:

  • CLI : Colored terminal output with lock types, timing, and risk scores
  • JSON : Structured, versioned schema for programmatic consumption
  • SARIF : For GitHub Code Scanning and IDE integration
  • Markdown : For documentation, wikis, or PR comments

SARIF output is particularly useful — it integrates with GitHub's Code Scanning to show violations directly in the "Files changed" tab of pull requests. Squawk outputs in text, TSV, and JSON formats.

Rule Overlap

Most of Squawk's 32 rules have equivalents in MigrationPilot. Here are the key mappings:

Check Squawk MigrationPilot
CREATE INDEX without CONCURRENTLY prefer-create-index-concurrently MP001
NOT NULL without default adding-not-nullable-field MP002
Volatile default value adding-field-with-default MP003
Column type change changing-column-type MP007
SET NOT NULL adding-required-field MP018
FK without NOT VALID adding-foreign-key-constraint MP005
DROP INDEX without CONCURRENTLY prefer-drop-index-concurrently MP009
SERIAL vs IDENTITY prefer-identity MP015

The overlap confirms that both tools catch the most critical migration safety issues. The difference is in coverage breadth: MigrationPilot has 48 additional rules for patterns that Squawk does not check.

CI Integration

Both tools provide GitHub Actions. Here is how they look in a workflow:

Squawk GitHub Action

- uses: sbdchd/squawk-action@v1
  with:
    pattern: "migrations/*.sql"
Enter fullscreen mode Exit fullscreen mode

MigrationPilot GitHub Action

- uses: mickelsamuel/migrationpilot@v1
  with:
    paths: "migrations/*.sql"
    fail-on: critical
Enter fullscreen mode Exit fullscreen mode

Both actions post comments on pull requests with the violations found. MigrationPilot additionally provides inline annotations in the "Files changed" tab and a Job Summary with aggregate metrics. Squawk's action is simpler and more focused.

Known Limitations

Squawk's known issues

  • Cannot analyze PL/pgSQL function bodies or DO blocks (GitHub issues #411, #528)
  • False positives in some valid contexts (#937, #973)
  • Exit code 1 for both errors and warnings — no way to distinguish (#348)
  • No cross-file validation or schema-level context
  • Pre-commit integration has been broken since June 2024 (#363)

MigrationPilot's known issues

  • New project — fewer real-world battle-testing hours
  • TypeScript is slower than Rust on very large files (sub-second for typical use)
  • Small community — fewer contributors finding and fixing edge cases
  • 3 rules behind a paywall ($19/month for production context analysis)
  • No dynamic lock tracing (purely static analysis, like Squawk)

When to Use Squawk

  • You want a proven, battle-tested tool. Squawk has years of production usage and a larger community. If stability and track record matter most, use Squawk.
  • You want 100% free with zero paid components. Squawk is fully free with no paid tier.
  • You need Rust-native speed. If you lint thousands of migration files in CI, Squawk's Rust parser is faster.
  • You want minimal dependencies. Squawk is a single binary. MigrationPilot requires Node.js.

When to Use MigrationPilot

  • You want the most comprehensive rule set. 80 rules cover patterns that Squawk's 32 rules do not check.
  • You want lock type information. Knowing which lock a statement acquires helps you assess real-world impact.
  • You want auto-fix. 12 rules can be automatically fixed with --fix.
  • You want SARIF output for GitHub Code Scanning. Violations appear directly in PR diffs.
  • You need production context analysis. Table size and query impact awareness (paid tier) is unique to MigrationPilot.
  • You want config presets. Five built-in presets (recommended, strict, ci, startup, enterprise) for different deployment contexts.

Can You Use Both?

Yes. Both tools analyze plain SQL files and can run independently in CI. Running both gives you the union of their rule sets and two independent opinions on each migration. The overhead is minimal — both complete in under a second for typical migrations.

# Run both in CI

  • name: Squawk lint
    uses: sbdchd/squawk-action@v1
    with:
    pattern: "migrations/*.sql"

  • name: MigrationPilot lint
    uses: mickelsamuel/migrationpilot@v1
    with:
    paths: "migrations/*.sql"
    fail-on: critical

Enter fullscreen mode Exit fullscreen mode




Summary

  • Squawk is the established choice: proven, fast, 100% free, and sufficient for catching the most common PostgreSQL migration hazards.
  • MigrationPilot offers more coverage: 80 vs 32 rules, lock type classification, auto-fix, risk scoring, and SARIF output. But it's newer and less battle-tested.
  • Both tools catch the critical issues (missing CONCURRENTLY, volatile defaults, column type changes, SET NOT NULL).
  • The core rules overlap significantly. The difference is in the long tail of less common but still dangerous patterns.
  • If stability and simplicity matter most, use Squawk. If coverage and features matter most, try MigrationPilot. If you want maximum safety, use both.

Top comments (0)