Changelog
Every release, newest first: new rules, auto-fixes, integrations and security fixes. This page renders the CHANGELOG.md in the repository, so it cannot drift from what actually shipped.
v1.6.1
Everything in 1.6.1 is the integration layer around an engine that already worked. A fresh-user test of every install path found the analysis correct every time and the wiring broken in four places; these are those fixes.
Fixed
- The pre-commit hook is no longer dead on arrival. Installed through the pre-commit framework, the launcher resolved the repo's own unbuilt checkout instead of the published CLI and failed on every commit with "could not find the MigrationPilot CLI". The launcher (
migrationpilot-precommit1.0.1) now depends on the engine under an aliased name so the collision cannot happen, verified against a real pre-commit run --format jsonnow validates against its own published schema. The output was correct but the schema atreport-v1.jsonwas missing thereversibilityandsequencekeys underadditionalProperties: false, so any CI that validated the output failed. A drift test now validates real output against the real schema on every buildsimulateis reachable fromnpx. It resolved PGlite only in the CLI's own install scope and told local users to run an install that then didn't help; it now also looks in the invoking project, and the error names the working command per install path- MP001's explanation was factually wrong — it claimed
CREATE INDEXwithoutCONCURRENTLYtakes an ACCESS EXCLUSIVE lock and blocks reads. It takes SHARE and blocks writes only, which the lock table in the same report already said correctly - The safe-index recipe the tool recommends now passes the tool. MP001's suggested fix used to trip MP023 and MP070;
--fixinserted astatement_timeoutthat would kill a realCONCURRENTLYbuild and leave the invalid index MP070 warns about. The one canonical recipe (alock_timeout, drop-first, nostatement_timeout, noIF NOT EXISTS) now analyzes GREEN end to end, and MP070 keeps firing on the unsafeIF NOT EXISTSform — closing a hazard the benchmark had already recorded as a miss - The GitHub Action survives a read-only workflow token. A new repository's default token can't list a PR's changed files or post a comment; the Action used to die on that 403 before analyzing anything. It now falls back to globbing the checked-out tree, warns with the exact
permissions:block to add, and still produces the verdict, SARIF, and annotations - The PR comment is now actionable — every violation carries
file:line(so one rule firing on three identical statements is three distinct bullets), each statement's Risk cell escalates to red when it carries a critical instead of contradicting a red header, and the score breakdown explains that the headline is the worse of two tracks rather than their sum - Plain DML no longer suggested for exclusion, and
--excludeis never offered for critical findings
Changed
- The install docs name the tag that exists (
ghcr.io/…:1, not:v1), the Windows Git Bash mount line, thepermissions:block every fresh repo needs, and the honest SARIF-upload story; the Homebrew line is gone until a tap exists /docs/cli-referencedocuments every command the CLI ships
v1.6.0
New Rules (29 rules, 83 → 112 total)
Schema and data safety (MP084–MP099):
- MP084
require-default-for-not-null-column— addingNOT NULLwithout a default breaks concurrent inserts mid-deploy - MP085
warn-grant-widening— flagsGRANTstatements that widen privileges inside a migration - MP086
require-explicit-on-delete— foreign keys should state theirON DELETEbehavior instead of inheritingNO ACTIONsilently - MP087
ban-volatile-check-constraint— CHECK constraints calling volatile functions pass validation and then corrupt silently - MP088
require-analyze-after-backfill— large backfills leave the planner with stale statistics untilANALYZE - MP089
warn-collation-change-rewrite— column collation changes rewrite the table underACCESS EXCLUSIVE - MP090
warn-trigger-on-hot-table— new triggers add per-row cost; skips the expand-contract sync-trigger pattern - MP091
warn-privilege-drift—REVOKE/ALTER DEFAULT PRIVILEGESin migrations drift from the source of truth - MP092
require-partitioned-index-strategy— indexes on partitioned parents need the two-stepON ONLY+ attach pattern - MP093
warn-default-partition-growth— rows landing in the default partition make futureATTACH PARTITIONscans grow unbounded - MP094
require-attach-partition-check—ATTACH PARTITIONwithout a matching CHECK constraint scans the whole partition under lock - MP095
warn-set-tablespace-rewrite—SET TABLESPACEcopies the entire relation while holding its lock - MP096
warn-matview-with-data—CREATE MATERIALIZED VIEW ... WITH DATAruns the full query inside the migration - MP097
ban-drop-constraint-backing-index— dropping an index that backs a constraint fails; ownership is settled from evidence, not the index name - MP098
warn-set-schema—SET SCHEMAbreaks every unqualified reference at once - MP099
warn-security-definer-search-path—SECURITY DEFINERfunctions without a pinnedsearch_pathare a privilege-escalation vector
Production-context catalog (MP100–MP112, need --database-url, all free):
- MP100
warn-redundant-index— the new index duplicates an existing one's key prefix - MP101
warn-index-on-write-hot-table— index builds on write-hot tables compete with every insert - MP102
warn-rewrite-disk-headroom— a table rewrite needs as much free disk as the table itself - MP103
warn-replication-lag-risk— long scans on large tables stall physical replicas - MP104
warn-long-index-build— predicts index build time from live row counts - MP105
warn-timescale-hypertable-ddl— DDL on a hypertable touches every chunk - MP106
prefer-timescale-drop-chunks—drop_chunks()beatsDELETEon time-series data - MP107
warn-citus-distributed-ddl— DDL on Citus-distributed tables fans out to every shard - MP108
warn-partman-managed-parent— pg_partman-managed parents should be changed through partman, not raw DDL - MP109
require-vector-index-params— pgvector HNSW indexes need explicit build parameters (works offline) - MP110
warn-partitioned-parent-fanout— parent-table DDL multiplies across live partitions - MP111
warn-timescale-columnstore-ddl— DDL on compressed columnstore chunks fails or decompresses - MP112
warn-hnsw-build-memory— HNSW builds exceedingmaintenance_work_memspill and crawl
Added
simulate— replays a migration against an in-process PostgreSQL (PGlite) and reports what actually happens, including errors static analysis cannot see- Cross-file sequence analysis on
check—--sequence,--fail-on-sequence,--lock-budget: orders files, tracks locks across the whole set, and flags sequence-level hazards (SQ rules) plan-fix— turns a violation report into an ordered, multi-deploy remediation planpredict— estimates lock durations and blast radius from production statisticstemplate— generates known-safe migration skeletons for common changesprecommitcommand,.pre-commit-hooks.yaml, and themigrationpilot-precommitlauncher package- Zero-config framework detection —
checkrecognizes 14 frameworks from the repo layout;--frameworkand--from-commandfor explicit control --fail-on irreversibleand rollback grading — gate on migrations that cannot be rolled back- Auto-fix grew from 12 to 20 rules — MP005, MP012, MP025, MP038, MP039, MP042, MP074, MP077 join
--fix - MCP
check_before_apply— the gate an agent calls before writing or running DDL. Resolves the project's own config exactly like the CLI and returns apass/failverdict with the blocking rule IDs named - MCP
analyze_migration_dirand MCPget_rule - Claude Code plugin (
integrations/claude-code/) — a migration-safety skill plus aPreToolUsehook that blocks unsafe DDL before it lands. Fails open when MigrationPilot is unavailable - Cursor and Copilot instruction files (
integrations/cursor/,integrations/copilot/) - Docker image (
ghcr.io/mickelsamuel/migrationpilot), single-file binaries on GitHub Releases, a GitLab CI template (integrations/gitlab/), and a Homebrew formula - The Migration Safety Handbook (
docs/handbook/) — 20 chapters; every lab executed on real PostgreSQL 17 and 18 - Published benchmark (
bench/) — 56-file labelled corpus, ground-truth scoring, results and misses published;node bench/run.mjsreproduces it - The lock-queue lab (
labs/lock-queue/) — measured traces of a blocking vs. safe schema change on PostgreSQL 18.4 with raw data and reproduction scripts
Changed
- Everything is free. The Pro tier is gone from the code, not just the pricing page: the Action no longer strips rules without a license key, the 3-per-month production-context meter is deleted, and no command prints an upsell. 97 rules run offline; 15 read production context via
--database-url; a license key is accepted for compatibility but decides nothing - The risk headline now weighs violations. Any critical finding drives the score to RED (one critical = 70, four or more = 100); warnings alone cap at YELLOW. Previously the headline could not reach RED without a database connection, whatever the findings said. Exit codes are unchanged. Semantics documented in
docs/risk-scoring.md - Precision pass on five rules after benchmark review: MP058 no longer asks you to merge ALTERs the handbook requires apart; MP070/MP097 settle index ownership from evidence; MP003 names the real default expression and describes the rewrite truthfully; MP090 skips the expand-contract sync-trigger pattern
- Statement kind is now detected from the parse tree, never the leading keyword — a comment above
BEGINno longer disables transaction-aware rules
Fixed
- Plain DML no longer classifies as ACCESS EXCLUSIVE. The lock classifier fell through to the worst case for anything it didn't recognize, so a bare
SELECTwas reported as a critical lock hazard. SELECT now takes ACCESS SHARE (ROW SHARE with a locking clause); INSERT/UPDATE/DELETE/MERGE take ROW EXCLUSIVE; COPY follows its direction - MP043 read the wrong parser subtype — it missed the
ALTER DOMAIN ADD CONSTRAINTit is named for and fired onSET DEFAULTinstead;NOT VALIDdomain constraints are now the recognized escape hatch - MP052's rename branch was unreachable — it never fired on
ALTER TABLE ... RENAME COLUMN; it does now - MP048 matched 'now' as a substring, so
SET DEFAULT 'nowhere'was flagged as volatile; it now walks the parsed expression, and also recognizesCURRENT_TIMESTAMP-family keywords as the volatile calls they are - MP046's fixer emitted SQL the server rejects (
DETACH PARTITION CONCURRENTLY p— the keyword goes after the partition name) - Violation line numbers — wrong since v1.1.0 for any statement not starting at the file's first line; also fixed in SARIF (Code Scanning annotated the wrong lines), PR comments, JSON output, and the VS Code extension. Statements sharing a line no longer swap violations; MP061–MP066 no longer hardcode line 1
- License key expiry was stamped from local date parts but parsed as UTC, expiring keys a day early west of Greenwich
- PR comments: multi-line statements no longer break the report table; the footer states what
--database-urladds instead of advertising a discontinued trial - MP040's fixer emitted invalid SQL for
TIMESTAMPTZcolumns; MP023's fixer output now parses - Sequence summaries pluralize correctly
v1.5.1
Fixed
- Windows: prevent a libuv
UV_HANDLE_CLOSINGcrash on multi-statement analyze - Checkout fulfillment: send product metadata so the webhook issues license keys, email the expiry the key was actually signed with, and retry delivery when the license email fails
- Publish workflow no longer masks npm publish failures
Added
migrationpilot-mcplauncher package on npm —npx migrationpilot-mcpstarts the MCP server- Experimental
mutation-testcommand — mutates known-good migrations into dangerous near-neighbours and reports which ones your current config would allow /playgroundnow runs the full 83-rule analysis client-side in the browser; SQL never leaves the page
Changed
- All 83 rules are free, including the production-context rules (MP013, MP014, MP019); Pro/Team plans replaced by a single per-organization plan
- Dependency refresh across CLI, site, and VS Code extension; all security advisories cleared
v1.5.0
New Rules (3 rules, 80 → 83 total)
PostgreSQL 18 Support (MP081, MP082, MP083):
- MP081
prefer-pg18-not-null-not-valid— On PG18+, use nativeSET NOT NULL NOT VALIDinstead of the old CHECK constraint workaround - MP082
warn-not-enforced-constraint— Warn when usingNOT ENFORCEDconstraints (PG18+), which skip validation entirely - MP083
warn-fk-nondeterministic-collation— Detect foreign keys on columns using non-deterministic (ICU) collations, which PG18 rejects
Blog
- New article: "PostgreSQL 18 Changed NOT NULL — Update Your Migration Rules"
v1.4.1
Security
- Plugin loader — Enforce project root boundary on plugin paths to prevent directory traversal
- Auth tokens — Reject unencrypted legacy tokens (forces re-login for old token format)
- VS Code extension — Disable trusted markdown mode in hover tooltips (prevents command URI injection)
- GitHub Action — Sanitize glob patterns to prevent regex injection and ReDoS
- GitHub Action — Mask database-url in Actions logs via
core.setSecret() - GitHub Action — Block fork PRs from running local action in migration-check workflow
- Playground — Add 50KB input size limit and sanitize parser error messages
- Production queries — Escape regex metacharacters in table names for
pg_stat_statementsqueries - Pre-commit hook — Fix unquoted shell variable to prevent word-splitting on filenames with spaces
- Dependencies — Patch rollup path traversal (GHSA-mw96-cpmx-2vgc), minimatch ReDoS, hono auth bypass via pnpm overrides
- CI — Pin mcp-publisher binary to specific release version instead of
latest
Improvements
- MCP Registry support — Added
server.jsonandmcpNamefield for official MCP Registry listing - CI — Added automated MCP Registry publishing to release workflow
v1.4.0
New Rules (14 rules, 66 → 80 total)
Lock Safety (MP069, MP072, MP073):
- MP069: warn-fk-lock-both-tables - FK constraint locks both source and referenced table simultaneously
- MP072: warn-partition-default-scan -
ATTACH PARTITIONscans DEFAULT partition under lock - MP073: ban-superuser-role -
ALTER SYSTEM/CREATE ROLE SUPERUSERin migrations is dangerous
Data Safety (MP067, MP071, MP080):
- MP067: warn-backfill-no-batching -
DELETEwithout WHERE clause locks entire table and bloats WAL - MP071: ban-rename-in-use-column -
RENAME COLUMNwithout updating dependent views/functions - MP080: ban-data-in-migration - DML (INSERT/UPDATE/DELETE) mixed with DDL in same migration
Best Practices (MP068, MP070, MP074-MP079):
- MP068: warn-integer-pk-capacity -
CREATE SEQUENCE AS integerrisks overflow — usebigint - MP070: warn-concurrent-index-invalid -
CREATE INDEX CONCURRENTLYcan leave invalid index on failure - MP074: require-deferrable-fk - FK constraints should be
DEFERRABLEfor bulk loading - MP075: warn-toast-bloat-risk -
UPDATEon TOAST columns causes bloat from full-row copies - MP076: warn-xid-consuming-retry -
SAVEPOINTcreates subtransactions consuming XIDs rapidly - MP077: prefer-lz4-toast-compression - Use
lz4overpglzfor TOAST compression (PG 14+) - MP078: warn-extension-version-pin -
CREATE EXTENSIONwithoutVERSIONis non-deterministic - MP079: warn-rls-policy-completeness - RLS policies don't cover all operations
New Features
VS Code Extension (vscode-migrationpilot/):
- Real-time diagnostics on save with severity-mapped squiggles
- Hover tooltips showing rule details, why it matters, safe alternatives
- Quick fix actions for 12 auto-fixable rules + inline disable comments
- Configurable PG version, rule exclusion, and file patterns
- 130KB bundled with esbuild
Browser Playground (site/src/app/playground/):
- Interactive SQL editor with 5 example migrations
- Server-side analysis via Next.js Server Actions
- PG version selector (10-20), risk badges, violation cards
- Zero data storage — runs entirely on Vercel
Analysis Features:
- Schema state simulation — In-memory DDL replay tracking tables, columns, indexes, constraints, sequences
- Cross-migration dependency graph — Directed edges between files, cycle detection via DFS, orphan identification
- Migration duration prediction — Heuristic-based estimates calibrated with table stats (row count, size, indexes)
- Lock queue simulation — Models blocked operations, queue buildup time, and actionable recommendations
- Trigger cascade analysis — Static and DB-backed cascade chain discovery with depth limits
- Sequence overflow monitoring — Static analysis of CREATE SEQUENCE types + DB-backed current value checking
Expand-Contract Templates (template command):
- 5 operations:
rename-column,change-type,split-table,add-not-null,remove-column - 3-phase output (expand, migrate, contract) with proper timeouts and batch processing
--phaseflag to output a single phase
Custom Rules Engine (src/plugins/):
- ESLint-style plugin loading from local files or npm packages
- Validates rule IDs to prevent collision with built-in
MPprefix - Default severity assignment for plugins missing severity field
Shareable Config Presets (5 total):
migrationpilot:recommended— Default balanced settingsmigrationpilot:strict— All 83 rules at critical severitymigrationpilot:ci— CI-optimized defaultsmigrationpilot:startup— Disables nitpicky rules for early-stage teamsmigrationpilot:enterprise— Maximum safety with audit logging and lower thresholds
Enterprise Features:
- Team management — Org-level seat tracking, member registration, activity logging, centralized config fetching
- Policy enforcement — Required rules, severity floors, blocked SQL patterns, review-required patterns
- SSO authentication — Device code flow for CLI login, API key auth, token management
teamcommand — Show organization status, seats, members, and recent activitylogin/logoutcommands — Authenticate via SSO or API keypolicycommand — Check migration files against organization policiesteamandpolicyconfig sections in.migrationpilotrc.yml
CLI Improvements:
templatecommand — Generate expand-contract migration templatespredictcommand — Estimate migration duration with optional table stats- Next-step suggestions after analysis (Rust compiler-inspired)
- 20 commands total (was 14)
Pricing Restructure:
- Pro: $29 → $19/month ($24 → $16/month annual)
- New Team tier: $49/month ($42/month annual), up to 10 seats
- 4-tier structure: Free, Pro, Team, Enterprise
Quality
- 970+ tests across 54 test files
- Build clean: CLI 1.0MB, Action 1.6MB, API 390KB, MCP 1.2MB
- Typecheck clean, lint clean
- 14 new rule documentation pages (docs/rules/MP067-MP080.md)
- 17 VS Code extension tests
- 33 enterprise feature tests (team, policy, SSO)
v1.3.0
New Rules (18 rules, 48 → 66 total)
Lock Safety (MP049, MP055):
- MP049: require-partition-key-in-pk - Partitioned table PK must include all partition key columns
- MP055: drop-pk-replica-identity-break - Dropping PK breaks logical replication when table uses default REPLICA IDENTITY
Best Practices (MP050-MP051, MP056, MP058-MP059):
- MP050: prefer-hnsw-over-ivfflat - HNSW provides better recall without training data or reindexing
- MP051: require-spatial-index - Spatial/geometry columns need GIST or SP-GIST indexes
- MP056: gin-index-on-jsonb-without-expression - Plain GIN index on JSONB column useless for ->> operator queries
- MP058: multi-alter-table-same-table - Multiple ALTER TABLE on same table causes unnecessary lock cycles
- MP059: sequence-not-reset-after-data-migration - INSERT with explicit IDs without setval() causes duplicate key errors
Dependency & Transaction Safety (MP052-MP054):
- MP052: warn-dependent-objects - DROP/ALTER COLUMN may break views, functions, or triggers
- MP053: ban-uncommitted-transaction - BEGIN without matching COMMIT leaves open transaction
- MP054: alter-type-add-value-in-transaction - New enum value not visible until COMMIT
Replication Safety (MP057, MP060):
- MP057: rls-enabled-without-policy - ENABLE ROW LEVEL SECURITY without CREATE POLICY silently denies all access
- MP060: alter-type-rename-value - RENAME VALUE breaks logical replication subscribers
Performance (MP061):
- MP061: suboptimal-column-order - Variable-length columns before fixed-size columns wastes alignment padding
Safety (MP062):
- MP062: ban-add-generated-stored-column - Adding a stored generated column causes full table rewrite under ACCESS EXCLUSIVE lock
Static Analysis (MP063):
- MP063: warn-do-block-ddl - DO block contains DDL that bypasses static analysis — lock impact cannot be determined
Operations Safety (MP064-MP065):
- MP064: ban-disable-trigger - DISABLE TRIGGER breaks replication, audit logs, and FK enforcement
- MP065: ban-lock-table - Explicit LOCK TABLE blocks queries and can cause deadlocks
Maintenance (MP066):
- MP066: warn-autovacuum-disabled - Disabling autovacuum causes table bloat and risks transaction ID wraparound
New Commands
doctor- Diagnostic checks (Node version, config, latest version, framework, license)completion <shell>- Shell completion scripts for bash, zsh, and fishdrift- Compare two database schemas to detect drift between environmentstrends- Historical analysis of migration safety trends over timeexplain <rule>- Show detailed information about a specific rulerollback <file>- Generate reverse DDL for migration rollback
New Features
- MCP Server — Model Context Protocol server with 4 tools (
analyze_migration,suggest_fix,explain_lock,list_rules) for AI assistant integration - Schema Drift Detection — Compare two database schemas via
information_schemato find missing tables, columns, indexes, and constraints - Historical Analysis — JSONL-based storage of analysis results with trend computation
- Audit Logging — JSONL event log for enterprise compliance, configurable path, CI/user/timestamp enrichment
- Air-Gapped Mode —
--offlineflag skips update checks and production context for regulated environments - Free Usage Tracking — 3 production analyses per month on free tier with contextual upgrade prompts
- 14-Day Free Trial — Pro trial via Stripe Checkout with no credit card required upfront
- Annual Pricing — ~17% discount ($24/mo billed annually vs $29/mo monthly)
- Shell Completions — bash, zsh, and fish completion scripts via
migrationpilot completion - Star Prompt — One-time "Star on GitHub" message after first analysis with violations (suppressed in CI)
- Update Checker — npm registry version check with 24h cache in
~/.migrationpilot/
New Auto-Fixes (6 → 12 rules)
- MP021:
REINDEX→REINDEX CONCURRENTLY - MP023:
CREATE TABLE/INDEX→CREATE TABLE/INDEX IF NOT EXISTS - MP037:
VARCHAR(n)→TEXT - MP040:
TIMESTAMP→TIMESTAMPTZ - MP041:
CHAR(n)→TEXT - MP046:
DETACH PARTITION→DETACH PARTITION CONCURRENTLY
CLI Improvements
--output <file>flag onanalyzeandcheck— write report to file while showing summary on stdout--offlineflag onanalyzeandcheckcommands for air-gapped deployment--no-configflag to skip config file loadinginit --preset <name>flag for quick configuration (recommended, strict, ci)init --forceflag to overwrite existing config files- Config file validation — warns on unknown keys in
.migrationpilotrc.yml - Post-analysis messages (update check, star prompt) with CI-aware suppression
GitHub Action Improvements
- Inline annotations — violations appear directly in the PR diff "Files changed" tab
- Job Summary — rich markdown summary with metrics and violations table in the Actions tab
- New
excludeinput — comma-separated list of rules to skip (e.g.MP001,MP004) - New
config-fileinput — path to.migrationpilotrc.yml(auto-detected if not specified) - Config-driven severity overrides in Action context
- Expired license warning with renewal link
- Paginated PR comment lookup (handles repos with 100+ comments)
Programmatic API
- New exports:
autoFix,isFixable(auto-fix engine),detectFrameworks(framework detection)
Documentation
- 31 documentation pages on landing site (6 core docs + 14 framework guides + 9 provider guides + rules index + pricing)
- Dedicated
/pricingpage with tier comparison, annual toggle, and FAQ - Rules index page (
/docs/rules) with all 66 rules categorized /migrate-from-atlaslanding page — rule mapping, feature comparison, migration guide/migrate-from-squawklanding page — 25-rule mapping, 18-feature comparison, migration guide- Enterprise landing page with security, compliance, SLA details
- GitLab CI and Bitbucket Pipelines example configurations
- Rule documentation for MP049-MP066 (18 files)
Quality
- 781+ tests across 48 test files
- 33 E2E CLI tests covering all major commands, flags, and performance
- 31 fixer tests covering all 12 auto-fix rules
- 20 MCP server tests covering all 4 tools
- 12 new rule tests for MP052-MP054
- 21 new rule tests for MP055-MP060
- 19 config tests including validation warnings and auditLog support
- Build clean: CLI 923KB, Action 1.5MB, API 274KB, MCP 1.2MB
- Site: 100+ pages (66 rules + 31 docs + enterprise + billing + migrate-from-atlas + migrate-from-squawk + misc)
v1.2.0
Security
- Switch license key signing from HMAC-SHA256 to Ed25519 asymmetric cryptography
- Remove Pro rules from programmatic API exports (only free rules publicly accessible)
- Add security headers to landing page (CSP, HSTS, X-Frame-Options, Referrer-Policy)
- Add CORS headers restricting API endpoints to migrationpilot.dev origin
- Fix error message leakage in checkout, billing-portal, and webhook APIs
- Add rate limiting and email validation to billing-portal endpoint
- Remove dist/ and internal config files from public repository
Improvements
- Add expired license warning with renewal link across all CLI commands
- Add
--license-keyoption to watch mode for Pro features - Drop Node 20 from CI matrix (EOL April 2026), require Node >= 22
v1.1.0
New Rules (23 rules, 25 → 48 total)
Lock Safety (MP026-MP033):
- MP026: ban-drop-table - DROP TABLE permanently removes table and data
- MP027: disallowed-unique-constraint - UNIQUE constraint without USING INDEX scans full table
- MP028: no-rename-table - Renaming tables breaks queries, views, FKs
- MP029: ban-drop-not-null - DROP NOT NULL may break app assumptions
- MP030: require-not-valid-check - CHECK constraint without NOT VALID (auto-fixable)
- MP031: ban-exclusion-constraint - EXCLUSION constraint under ACCESS EXCLUSIVE
- MP032: ban-cluster - CLUSTER rewrites table under ACCESS EXCLUSIVE
- MP033: require-concurrent-refresh-matview - REFRESH MATERIALIZED VIEW without CONCURRENTLY (auto-fixable)
Data Safety (MP034-MP036):
- MP034: ban-drop-database - DROP DATABASE in migration files
- MP035: ban-drop-schema - DROP SCHEMA permanently removes schema
- MP036: ban-truncate-cascade - TRUNCATE CASCADE across FK-referencing tables
Best Practices (MP037-MP045, MP048):
- MP037: prefer-text-over-varchar - VARCHAR(n) has no benefit over TEXT in PostgreSQL
- MP038: prefer-bigint-over-int - INT PK/FK can overflow, use BIGINT
- MP039: prefer-identity-over-serial - SERIAL quirks, use GENERATED ALWAYS AS IDENTITY
- MP040: prefer-timestamptz - TIMESTAMP without TZ causes timezone bugs
- MP041: ban-char-field - CHAR(n) wastes space and causes comparison bugs
- MP042: require-index-name - Unnamed indexes are hard to reference
- MP043: ban-domain-constraint - Domain constraints validate against ALL using columns
- MP044: no-data-loss-type-narrowing - Narrowing column type risks data loss
- MP045: require-primary-key - Tables without PK break replication
- MP048: ban-alter-default-volatile - Volatile SET DEFAULT on existing column is misleading
Advanced (MP046-MP047):
- MP046: require-concurrent-detach-partition - DETACH PARTITION without CONCURRENTLY (PG 14+)
- MP047: ban-set-logged-unlogged - SET LOGGED/UNLOGGED rewrites entire table
Auto-fix
- 2 new auto-fixable rules: MP030 (NOT VALID on CHECK) and MP033 (CONCURRENTLY on matview refresh)
- Total auto-fixable rules: 6 (MP001, MP004, MP009, MP020, MP030, MP033)
CLI Improvements
- New
list-rulescommand with--jsonoption --exclude <rules>flag to skip specific rules (comma-separated)- Enriched
--versionoutput (node version, platform, rule count) NO_COLORenv var andTERM=dumbdetection for color disabling
PG-Version-Aware Rule Updates
- MP002: PG 18+ recommends
SET NOT NULL NOT VALID+VALIDATE NOT NULL - MP003: PG 11+ note about volatile vs non-volatile defaults
- MP015: PG 10+ recommends
GENERATED ALWAYS AS IDENTITYover SERIAL - MP018: PG 18+ recommends
NOT NULL NOT VALIDapproach - MP039: Only flags on PG >= 10 (IDENTITY not available before)
- MP046: Only flags on PG >= 14 (DETACH CONCURRENTLY not available before)
Config
extendsfield for shareable config presets- 3 built-in presets:
migrationpilot:recommended,migrationpilot:strict,migrationpilot:ci - Strict preset: all rules at critical severity, fail on warning
Package Metadata
- Added
bugs,funding,packageManagerfields - Expanded keywords for npm discoverability
- Fixed TypeScript resolution order in exports (
typesbeforeimport)
Documentation
- Complete README rewrite with all 48 rules, comparison table, all features
- Per-rule documentation in
docs/rules/(48 files) - Landing page updated with v1.1.0, 48 rules, 9 feature cards, grouped rules display
.env.exampleand.editorconfigadded
Quality
- 550+ tests across 31 test files
- All 23 new rules have full test coverage
- Build clean: CLI 835KB, Action 1.2MB, API 219KB
---
v1.0.0
Core Engine
- DDL parser powered by libpg-query (WASM) for accurate PostgreSQL AST analysis
- Lock type classifier mapping every DDL operation to its PostgreSQL lock level
- Risk scoring engine with RED/YELLOW/GREEN levels based on lock impact and production context
Safety Rules (25 rules)
- MP001: require-concurrent-index - CREATE INDEX must use CONCURRENTLY
- MP002: require-check-not-null - SET NOT NULL needs CHECK constraint pattern
- MP003: volatile-default-rewrite - Volatile defaults cause full table rewrite (PG < 11)
- MP004: require-lock-timeout - DDL must have lock_timeout set
- MP005: require-not-valid-fk - Foreign keys must use NOT VALID + VALIDATE
- MP006: no-vacuum-full - VACUUM FULL blocks all queries
- MP007: no-column-type-change - Column type changes rewrite the table
- MP008: no-multi-ddl-transaction - Multiple DDL in one transaction compounds lock time
- MP009: require-concurrent-drop-index - DROP INDEX should use CONCURRENTLY
- MP010: no-rename-column - Renaming columns breaks running queries
- MP011: no-add-column-default-volatile - Volatile defaults on existing columns cause rewrite
- MP012: no-enum-add-value-in-transaction - ALTER TYPE ADD VALUE cannot run in a transaction
- MP013: high-traffic-table-ddl - DDL on high-traffic tables (Pro)
- MP014: large-table-ddl - DDL on tables > threshold rows (Pro)
- MP015: no-add-column-serial - SERIAL creates implicit sequence with ACCESS EXCLUSIVE
- MP016: require-index-on-fk - Foreign key columns need indexes
- MP017: no-drop-column - DROP COLUMN acquires ACCESS EXCLUSIVE lock
- MP018: no-force-set-not-null - SET NOT NULL needs CHECK pattern on PG 12+
- MP019: no-exclusive-lock-high-connections - ACCESS EXCLUSIVE with many active connections (Pro)
- MP020: require-statement-timeout - Long-running DDL needs statement_timeout
- MP021: require-concurrent-reindex - REINDEX needs CONCURRENTLY on PG 12+
- MP022: no-drop-cascade - CASCADE silently drops dependent objects
- MP023: require-if-not-exists - CREATE TABLE/INDEX need IF NOT EXISTS
- MP024: no-enum-value-removal - DROP TYPE destroys enum and dependent columns
- MP025: ban-concurrent-in-transaction - CONCURRENTLY in transaction always fails
CLI
- 7 commands:
analyze,check,plan,init,detect,watch,hook - Output formats: text (default), JSON (structured schema), SARIF v2.1.0, markdown
- Modes:
--quiet(gcc-style),--verbose(per-statement),--stdin(pipe input) - Auto-fix with
--fixand--fix --dry-run(MP001, MP004, MP009, MP020) --no-colorflag for CI environments- Config file support (
.migrationpilotrc.yml) - Inline disable comments (
-- migrationpilot-disable MP001) - Rule metadata: every violation includes "Why this matters" explanation and docs URL
- Performance timing in output footer
GitHub Action
- Analyzes migration files changed in PRs
- Posts/updates safety report as PR comment
- SARIF output for GitHub Code Scanning integration
- Configurable fail threshold (critical/warning/never)
Production Context (Pro tier)
- Query impact analysis via pg_stat_statements
- Table size awareness via pg_class/pg_stat_user_tables
- Active connection monitoring via pg_stat_activity
- Read-only: only queries pg_catalog system views
Developer Experience
- Programmatic API:
import { analyzeSQL } from 'migrationpilot' - TypeScript declarations included
- Migration framework auto-detection (14 frameworks)
- Watch mode with debounced file monitoring
- Git pre-commit hook installer (standalone + husky)
- Execution plan visualization with duration estimates
- Transaction boundary analysis
- Migration ordering validation
Billing
- Stripe Checkout integration for Pro subscriptions
- HMAC-SHA256 license key validation (client-side, no telemetry)
- Webhook-driven key generation with Resend email delivery
Quality
- 451 tests across 26 test files
- E2E tests spawning the actual CLI binary
- Snapshot tests for output format stability
- TypeScript strict mode with noUncheckedIndexedAccess
- ESLint clean, zero security vulnerabilities