no-drop-cascade
DROP ... CASCADE silently drops all dependent objects.
- operation
- Tables
- lock taken
- no table lock
- remediation
- Manual rewrite
- category
- Data safety
- Can lose data
- Breaks a rolling deploy
What triggers it
Fires on any DropStmt whose behavior is DROP_CASCADE — the check does not branch on removeType, so it covers DROP TABLE/TYPE/VIEW/... CASCADE uniformly.
What does not
A DROP without the CASCADE keyword returns null immediately, since the rule only compares drop.behavior against DROP_CASCADE; the default (RESTRICT-like) drop behavior never reaches the message.
Where it applies
Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.
The lock, and what it blocks
The rule does not evaluate lock behavior at all. Its concern is that CASCADE removes every dependent object — views, foreign keys, policies, triggers — in one statement, with nothing in the migration file listing what is about to go.
Why it matters
CASCADE silently drops views, indexes, constraints, and other objects that depend on the dropped object. This can cause unexpected data loss and application failures.
Unsafe, and safe
Flagged
DROP TABLE users CASCADE;
Safe alternative
-- Drop dependents explicitly first DROP VIEW IF EXISTS active_users; DROP TABLE users;
What it assumes
It cannot tell a deliberate, well-understood CASCADE (say, dropping a genuinely orphaned staging table) from an accidental one — it flags DROP_CASCADE every time, regardless of what actually depends on the object.
What backs this rule
Every rule is a claim about PostgreSQL, so it carries what the claim rests on: a handbook chapter that cites the manual, the incidents that put it there, and the version it was last checked against.
DROP TABLE is the only operation in this handbook with no recovery path.
- verified against
- PostgreSQL 17.10
- last checked
- 2026-08-11
- confidence
- Medium
PostgreSQL manual
What the CLI prints
⚠ [MP022] WARNING (line 1) DROP TABLE "users" CASCADE will silently drop all dependent objects (views, foreign keys, policies, triggers). Drop dependents explicitly instead. Safe alternative: -- First check dependent objects: -- SELECT deptype, classid::regclass, objid, objsubid -- FROM pg_depend -- WHERE refobjid = 'users'::regclass; -- Then drop dependents explicitly before the target: DROP TABLE users; Why: CASCADE silently drops all dependent objects without listing them: views, foreign keys, policies, and triggers. You may unintentionally destroy critical production objects that other services depend on. Docs: https://migrationpilot.dev/rules/mp022
Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.
Turning it off
For one statement, put a comment on the line before it:
-- migrationpilot-disable MP022 DROP TABLE users CASCADE;
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP022: false
# or keep it, and downgrade it
rules:
MP022:
severity: warningTry it
Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.
Run MP022 in the playground