Postgres ships five index types. Most apps only use one (B-tree, the default). Knowing the others unlocks 10-100x speedups on the right queries — and avoids creating useless indexes on the wrong ones.

Advertisement

B-tree — default workhorse

Equality and range queries on ordered data. Numbers, dates, strings, single-column or multi-column. ~99% of indexes you'll create. Default for primary keys, foreign keys, anything frequently filtered.

GIN — composite values

Indexing JSONB, arrays, full-text. Multiple keys per row (one row's array has many values, all indexed). Slow to update (good for read-heavy). Right answer for 'find all rows where tags contains X'.

Advertisement

BRIN — huge tables, correlated data

Stores summary per block range. Tiny (~1000x smaller than B-tree). Works when data is naturally ordered (time-series, append-only IDs). Bad if data is unordered. Useful for huge tables where B-tree is too big.

B-tree for normal queries, GIN for JSONB/arrays/FTS, BRIN for huge ordered data. Don't index by default — index by query plan.