All rules Rule BV001 · DS
PostgreSQL
critical
DS · Destructive changes
tier 2, needs a live schema
free in the CLI

Can I drop a column that other tables reference with a foreign key?

DROP COLUMN with live foreign-key references

Critical: this fails outright or takes production down.

What happens

Dropping a column that other tables' foreign keys point at either fails mid-migration or, with CASCADE, silently drops those constraints, leaving orphanable rows in dependent tables.

Why it is dangerous on a populated table

On an empty table this finishes before anyone notices. On a populated one the lock is held for the whole operation, every query on the table queues behind it, and the connection pool fills from the back.

Fires on

ALTER TABLE users DROP COLUMN id;

The safe pattern

Remove each dependent foreign key explicitly first, one reviewed, lock_timeout-guarded migration per referencing table, so nothing is dropped implicitly. Only drop the column itself a release after app code stopped reading it.

-- 1. Drop each referencing FK explicitly (repeat per dependent table):
SET lock_timeout = '5s';
ALTER TABLE orders DROP CONSTRAINT orders_user_id_fkey;
-- 2. A release later, once nothing reads the column:
--    ALTER TABLE users DROP COLUMN legacy_id;

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 (1)

drop referenced column
ALTER TABLE users DROP COLUMN id;

Stays silent (1)

drop unreferenced column
ALTER TABLE users DROP COLUMN nickname;

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