There is a particular kind of pull request that never gets applause: fifteen lines of SQL, a new column with a default, an index behind it. Nobody screenshots it. Nobody demos it. And yet in five years, when everything else in the codebase has been rewritten twice, that migration will still be true.
Every schema is a promise§
A migration is the only part of a system you cannot take back. Code can be reverted; data outlives its authors. So the discipline I hold myself to is simple: each migration must read like a contract clause — one concern, stated plainly, enforceable by the database itself rather than by good intentions in the application layer.
Constraints are documentation that cannot go stale. A CHECK clause is a comment the database is willing to fight for.
What boring looks like§
Boring means defaults on every new column so old rows stay valid. Boring means enums for closed sets and CHECK constraints for open ones. Boring means the trigger owns updated_at, because clients lie and clocks drift.
alter table public.posts
add column reading_time_minutes int not null default 1
check (reading_time_minutes >= 0);
create index idx_posts_status_published_at
on public.posts (status, published_at desc);None of that is clever. All of it is kind — to the reviewer, to the on-call engineer, and to whoever inherits the database after you. Cleverness ages like fruit; dullness ages like oak.
Letters to the editor
Correspondence