Learn Labs
Data Types

JSON & Arrays

JSONB, arrays, and when to reach for them

Beyond the fixed columns in Data Types, Postgres has first-class support for semi-structured data — useful, but easy to overuse.

json vs jsonb

payload json    -- stores exact text, re-parsed every time it's read
payload jsonb   -- stores a decomposed binary format, indexable

Querying jsonb

SELECT payload -> 'address' FROM events;          -- returns jsonb
SELECT payload ->> 'user_id' FROM events;          -- returns text
SELECT * FROM events WHERE payload @> '{"type": "signup"}';  -- containment
SELECT jsonb_path_query(payload, '$.items[*].sku') FROM events;

-> extracts a field as jsonb (keep chaining), ->> extracts as text (use it at the end of a chain when you need a plain value to compare or display). @> checks whether the left jsonb value contains the right one — this is what a GIN index accelerates; see Indexing.

Arrays

CREATE TABLE posts (
id   serial PRIMARY KEY,
tags text[]
);

INSERT INTO posts (tags) VALUES (ARRAY['sql', 'postgres', 'internals']);

SELECT * FROM posts WHERE 'postgres' = ANY(tags);
SELECT unnest(tags) FROM posts;  -- one row per array element

Arrays are a native type for any base type (integer[], text[], even jsonb[]), not an add-on — useful for small, denormalized lists that don't warrant a separate join table.

That closes out the Foundations and Data Types groups. Next up: Heap Storage — how a row you just inserted actually ends up on disk.

On this page