All rules Rule BV019 · TX
PostgreSQL
warning
TX · Transactions
hosted, paid, --remote

Can I add an enum value and use it in the same migration?

Enum value added inside a multi-statement migration

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

What happens

Adding an enum value has transaction restrictions: before Postgres 12 it errors inside a transaction block, and on 12+ the new value is unusable until the transaction commits. A migration runner that wraps the file in one transaction either fails outright or fails on the first statement that uses the new value.

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

ALTER TYPE order_status ADD VALUE 'archived';
UPDATE orders SET status = 'archived';

The safe pattern

Put ALTER TYPE ... ADD VALUE alone in its own migration so it commits before anything uses the value; statements that use the new value go in a later migration. On Postgres 12+ the statement is allowed inside a transaction, but the value stays unusable until that transaction commits, the split fixes both eras.

-- migration 1 (single statement, commits on its own):
ALTER TYPE order_status ADD VALUE IF NOT EXISTS 'archived';
-- migration 2 (later): statements that USE 'archived'

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)

enum mid migration
ALTER TYPE order_status ADD VALUE 'archived';
UPDATE orders SET status = 'archived' WHERE closed_at < now() - interval '1 year';

Stays silent (1)

enum alone
ALTER TYPE order_status ADD VALUE 'archived';

How to check locally

Catch this before it ships

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