Advanced Indexing Strategy: Going Beyond B-Tree with GIN, GiST, BRIN, and Partial Indexes

If you've worked with a relational database for any length of time, you already know the basic rule: add an index, queries get faster. What most developers don't learn until they hit a real performance wall is that not all indexes are the same tool. The default B-tree index that CREATE INDEX gives you is excellent for equality and range lookups on scalar, well-ordered data — but it's the wrong tool for JSONB documents, full-text search, geometric data, time-series tables, or queries that only ever touch a narrow slice of a huge table.

PostgreSQL ships with several index types specifically because different data shapes and query patterns need fundamentally different underlying data structures. This article walks through when and why to reach for GIN, GiST, BRIN, and partial indexes, with practical examples for each, so you can match the index type to the actual shape of your data instead of defaulting to B-tree everywhere and wondering why the query planner isn't using it.

A Quick Refresher: Why B-Tree Is the Default (and Its Limits)

According to the official PostgreSQL documentation on index types, CREATE INDEX creates a B-tree index by default because it fits the most common situations: equality and range comparisons (, , , , ), , , and / checks on data that can be sorted into a single linear order.