One of my favorite database design patterns is what I call the “mullet schema”: business up front, party in the back, where every table in the database ends with a JSON column.

I even mentioned it on a recent episode of the Talk Python podcast:

This morning, I read David Crawshaw’s excellent post, How I Program With Agents. In a sidebar, he completely blew my mullet-addled mind:

I learned an odd way of using SQL at Tailscale (from Brad and Maisem): make every table a JSON object. In particular, have only one “real” column and the rest generated from the JSON. So the typical table looks like:

CREATE TABLE IF NOT EXISTS Cookie (
  Cookie   TEXT    NOT NULL AS (Data->>'cookie')  STORED UNIQUE, -- PK
  UserID   INTEGER NOT NULL AS (Data->>'user_id') STORED REFERENCES User (UserID),
  Created  INTEGER NOT NULL AS (unixepoch(Data->>'created')) STORED,
  LastUsed INTEGER AS (unixepoch(Data->>'last_used')) CHECK (LastUsed>0),
  Data     JSONB   NOT NULL
);

Now it’s a party!

David mentions some of the tradeoffs and hints at a potential future blog post about the approach. In the meantime, I may need to rethink my mullet nomenclature!