Migration Checker
Catch dangerous PostgreSQL migration patterns before they reach production — right inside VS Code.
A DROP TABLE in production is irreversible. A DELETE without WHERE wipes your entire table. A migration without a transaction leaves your database half-broken. Migration Checker catches all of these before they ever leave your machine.
Features
- 🔴 Real-time SQL diagnostics — red and yellow underlines as you type, no manual scan needed
- 🛡️ Git protection — block dangerous migrations at
git add, git commit, and git push
- ⚡ CLI tool — run checks in CI/CD pipelines or from your terminal
- ⚙️ Configurable rules — tune severity per rule via
.migrationrc.json
Built-in Rules
Rules apply to two file types, detected automatically from the filename:
- Schema migrations —
<yyyymmddhhmmss>_<crud>_<object_type>_<schema>_<name>.sql
- Seed data —
<schema_name>.<table_name>.sql
Destructive Operation Rules
| Rule |
Default Severity |
Applies To |
What It Catches |
no-drop-table |
🔴 Error |
Schema migration |
DROP TABLE, DROP INDEX, DROP SCHEMA, DROP COLUMN and similar destructive statements |
no-delete-without-where |
🔴 Error |
Schema migration |
DELETE FROM with no WHERE clause — prevents accidental full table wipes |
no-update-without-where |
🔴 Error |
Schema migration |
UPDATE with no WHERE clause — prevents accidental full table updates |
no-truncate |
🔴 Error |
Schema migration |
TRUNCATE statements — irreversibly clears all rows |
Schema Safety Rules
| Rule |
Default Severity |
Applies To |
What It Catches |
require-timestamp-with-timezone |
🔴 Error |
Schema migration |
TIMESTAMP without WITH TIME ZONE — use TIMESTAMPTZ to prevent silent data corruption |
require-if-not-exists |
⚠️ Warning |
Schema migration |
CREATE TABLE or CREATE INDEX missing IF NOT EXISTS — prevents errors on re-runs |
no-create-index-without-concurrently |
⚠️ Warning |
Schema migration |
CREATE INDEX without CONCURRENTLY — locks the table and blocks reads/writes in production |
no-rename-column |
⚠️ Warning |
Schema migration |
ALTER TABLE ... RENAME COLUMN — breaks existing queries and application code |
no-set-not-null |
⚠️ Warning |
Schema migration |
ALTER TABLE ... SET NOT NULL — causes a full table scan and lock on large tables |
no-text-datatype |
⚠️ Warning |
Schema migration |
Columns defined as TEXT — use VARCHAR(n) with an explicit length instead |
require-datetime-columns-format |
🔴 Error |
Schema migration |
Date/time columns not following the required format convention |
Standards & Convention Rules
| Rule |
Default Severity |
Applies To |
What It Catches |
require-audit-columns |
⚠️ Warning |
Schema migration |
CREATE TABLE missing created_at, updated_at, created_by, updated_by |
require-operational-is-active |
🔴 Error |
Schema migration |
OPERATIONAL tables missing is_active BOOLEAN NOT NULL DEFAULT TRUE for soft delete support |
require-table-comments |
🔴 Error |
Schema migration |
CREATE TABLE without a COMMENT ON TABLE statement |
require-column-comments |
⚠️ Warning |
Schema migration |
Columns missing COMMENT ON COLUMN statements |
no-raw-password-column |
⚠️ Warning |
Schema migration |
Columns named password or similar storing plain-text passwords |
Migration Structure Rules
| Rule |
Default Severity |
Applies To |
What It Catches |
require-migrate-up-down |
🔴 Error |
Schema migration |
Missing -- migrate:up marker or missing protected -- migrate:down section with rollback-disabled comment |
require-valid-sql-file-name |
🔴 Error |
All files |
Filename does not match the required naming convention for schema migrations or seed data |
require-alter-table-separate-migration |
🔴 Error |
Schema migration |
ALTER TABLE and CREATE TABLE combined in the same file — each must be its own migration |
Seed Data Rules
| Rule |
Default Severity |
Applies To |
What It Catches |
require-merge-md5-hash |
⚠️ Warning |
Seed data |
MERGE or INSERT ... ON CONFLICT scripts not using md5() for row matching, or missing audit columns |
All rules are configurable. Set any rule to "error", "warning", "info", or "off" to disable it entirely.
Real-Time SQL Diagnostics
Migration Checker automatically activates on .sql files. As you edit, risky patterns are underlined instantly in the editor — no need to run a command or save the file first.
Hover over any underline to see:
- What the rule is
- Why it's dangerous
- How to fix it
Git Protection
Install hooks once and migrations are checked at every stage of your Git workflow.
# From the Command Palette (Ctrl+Shift+P):
Migration Checker: Install Git Protection
Or via the CLI:
migration-checker --install-hooks # pre-commit + pre-push hooks
migration-checker --install-git-wrapper # also block git add (optional)
source ~/.bashrc # activate the git add wrapper
Once installed:
| Stage |
Protection |
git add |
Shell wrapper blocks staging dangerous SQL (optional) |
git commit |
Pre-commit hook scans staged .sql files |
git push |
Pre-push hook runs a final scan before code leaves your machine |
If a dangerous pattern is found, the operation is blocked with a clear error message showing the file, line, and rule that failed.
CLI Usage
Run Migration Checker from the terminal or integrate it into your CI/CD pipeline.
# Check a specific file
migration-checker file.sql
# Check multiple files
migration-checker migrations/*.sql
# Check only staged SQL files (ideal for pre-commit)
migration-checker --staged
# Install Git hooks
migration-checker --install-hooks
# Install git add wrapper (optional, modifies shell profile)
migration-checker --install-git-wrapper
CI/CD Example (GitHub Actions)
- name: Check SQL migrations
run: npx migration-checker migrations/*.sql
The CLI exits with code 1 if any errors are found, making it easy to fail a pipeline on dangerous migrations.
Configuration
Create a .migrationrc.json file in your project root to customise rule severity:
{
"rules": {
"no-drop-table": "error",
"no-delete-without-where": "error",
"no-update-without-where": "error",
"no-truncate": "error",
"require-timestamp-with-timezone": "error",
"require-if-not-exists": "warning",
"no-create-index-without-concurrently": "warning",
"no-rename-column": "warning",
"no-set-not-null": "warning",
"no-text-datatype": "warning",
"require-datetime-columns-format": "error",
"require-audit-columns": "warning",
"require-operational-is-active": "error",
"require-table-comments": "error",
"require-column-comments": "warning",
"no-raw-password-column": "warning",
"require-migrate-up-down": "error",
"require-valid-sql-file-name": "error",
"require-alter-table-separate-migration": "error",
"require-merge-md5-hash": "warning"
},
"dialect": "postgresql"
}
Severity levels
| Value |
Behaviour |
"error" |
Shown as red underline, blocks Git operations |
"warning" |
Shown as yellow underline, does not block |
"info" |
Shown as blue underline, informational only |
"off" |
Rule disabled entirely |
Commands
Open the Command Palette (Ctrl+Shift+P) and search for:
| Command |
Description |
Migration Checker: Run Migration Checks |
Manually scan the active SQL file |
Migration Checker: Install Git Protection |
Install pre-commit and pre-push hooks |
Extension Settings
| Setting |
Default |
Description |
migrationChecker.enabled |
true |
Enable or disable the extension globally |
migrationChecker.gitProtection.autoInstall |
false |
Auto-install Git hooks on activation (off by default) |
migrationChecker.gitProtection.includeGitAddWrapper |
false |
Also install the git add shell wrapper |
migrationChecker.gitProtection.showNotifications |
true |
Show notifications about Git protection status |
Requirements
- VS Code
1.85.0 or higher
- Node.js (for CLI and Git hook usage)
- PostgreSQL migration files with
.sql extension
Why Migration Checker?
Most SQL mistakes are caught too late — during a code review, a staging deploy, or worse, in production. Migration Checker moves that safety check to the earliest possible moment: the second you write the code.
| Without Migration Checker |
With Migration Checker |
DROP TABLE caught in production |
Caught instantly in the editor |
DELETE without WHERE wipes the whole table |
Blocked before git commit |
CREATE INDEX locks production table |
Flagged — use CONCURRENTLY instead |
| Wrong timestamp type causes data loss |
Flagged as an error on save |
| Plain-text password column goes unnoticed |
Caught immediately as an error |
| Missing audit columns discovered in review |
Warned about while writing the migration |
License
MIT — see LICENSE for details.
Contributing & Issues
Contributors
Found a bug or want a new rule? Open an issue or pull request on the repository.
For rule requests, please include:
- The SQL pattern you want detected
- Why it's dangerous
- A minimal example