Lesson 7 · Internals & data structures
TOAST
How a big JSONB value fits in an 8 KB page — and why SELECT * can cost you.
Your win: explain how Postgres stores oversized column values, and draw
the practical lesson for your wide jsonb and array columns.
The problem: a tuple should fit in a page
A page is 8 KB (Lesson 5), and Postgres prefers a tuple to fit within one page. But
columns like a big jsonb document or a long text[] can be far
larger. The answer is TOAST — The Oversized-Attribute Storage
Technique.1
How it works
When a row's variable-length values would make it too big, Postgres transparently
compresses them and/or moves them out-of-line into a
separate TOAST table, leaving just a small pointer in the main tuple. It applies to
variable-length types (text, jsonb, bytea, arrays) —
never to fixed types like int. It's invisible to your SQL: you query the
column normally.
SELECT * — or selecting a large content
jsonb when you only need subject — pulls extra data from the TOAST table and
costs I/O you didn't need. Select only the columns you use.
emails.content (jsonb), conversation.latest_message /
optional_config (jsonb), and email_recipients (text[]) are all
TOAST-eligible. When they're large, they live out-of-line — so a list query that returns
only subject/status is much cheaper than one that drags
content along. This is a real, free win in list endpoints.
PostgreSQL — TOAST
The reference on out-of-line storage, compression, and storage strategies
(PLAIN/EXTENDED/EXTERNAL/MAIN).
Check yourself (from memory)
Q1. TOAST stores large column values…
Q2. TOAST applies mainly to…
text,
jsonb, bytea, arrays. Fixed types like int aren't TOASTed.
Q3. A practical consequence of TOAST is…
content you don't need wastes I/O. Select what you use.
SELECT *?SELECT * (or selecting a big
content jsonb when you only need subject) pulls extra data and
costs I/O. Select only the columns you need.EXTENDED vs EXTERNAL),
or how compression interacts with JSONB search? Ask me.