All rules Rule BV010 · DS
PostgreSQL
warning
DS · Destructive changes
free in the CLI

What does DROP ... CASCADE actually remove?

DROP with CASCADE hitting unexpected dependents

Warning: this works, but blocks traffic or rewrites data at scale.

What happens

CASCADE resolves the dependency graph at execution time and drops everything in it, without listing what it took. What it removes in production can differ from dev, a view or foreign key added since, gone silently.

Why it is dangerous on a populated table

It completes, but the time it holds its lock or rewrites rows scales with the table, and on a busy one that is long enough for traffic to queue.

Fires on

DROP TABLE legacy_events CASCADE;

The safe pattern

Run the DROP without CASCADE first: it fails and lists every dependent object. Then drop each dependent explicitly in the migration, so the blast radius is written down and reviewed instead of resolved silently at execution time.

-- DROP ... RESTRICT (the default) fails and names every dependent;
-- drop them explicitly so the migration says what it removes:
SET lock_timeout = '5s';
DROP VIEW legacy_events_summary;
-- then, once nothing references it (see BV005/BV030):
--    DROP TABLE legacy_events;

Fixtures

The rule ships with these files and the test suite runs them on every change: the first set must fire, the second must stay silent.

Fires (2)

drop column cascade
ALTER TABLE users DROP COLUMN profile_id CASCADE;
drop table cascade
DROP TABLE legacy_events CASCADE;

Stays silent (1)

plain drop
DROP TABLE legacy_events;

How to check locally

Catch this before it ships

This rule runs locally in the free CLI, or with the full corpus through the hosted service. No install, nothing leaves your machine:

npx bolvrk check migration.sql