Why is SET lock_timeout = 0 dangerous in a migration?
Timeout guard disabled with SET ... = 0
Warning: this works, but blocks traffic or rewrites data at scale.
What happens
SET lock_timeout = 0 (or statement_timeout = 0) switches the safety off: zero means 'wait forever'. A migration that disables its timeouts can queue behind one slow query indefinitely, with all new traffic queueing behind it, precisely the stall the guard exists to prevent.
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
SET statement_timeout = 0;
ALTER TABLE orders ADD COLUMN region text;The safe pattern
Set a short, finite timeout instead. If the operation legitimately needs long uninterrupted time (a large index build, say), that is a scheduled operational window, not a migration that silently waits forever whenever the lock is contended.
SET lock_timeout = '5s';
ALTER TABLE orders ADD COLUMN region text;
-- can't get the lock in 5s → fail fast, retry later; traffic never stallsFixtures
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)
SET statement_timeout = 0;
ALTER TABLE orders ADD COLUMN region text;Stays silent (1)
SET lock_timeout = '5s';
ALTER TABLE orders ADD COLUMN region text;How to check locally
This rule runs in the hosted service on Startup and above: add --remote with a team token, or use the GitHub Action. No install, nothing leaves your machine:
npx bolvrk check migration.sql --remote