One of the Postgres features our customers ask us for the most is full-text search. Today, we are excited to announce TIN: a fast, full-featured, reliable full-text search extension for Postgres. TIN stands for “Text INdex,” and that is what it does.

TIN is available immediately as a GA release for all Postgres and Neki databases. Check it out:

CREATE INDEX an_index_name ON table_name USING tin(text_column_name);
SELECT * FROM table_name
  WHERE text_column_name ==> 'some words';

We built TIN because we believe a good text index should support:

  • Boolean expressions, phrase queries, and span queries
  • Fuzzy, wildcard, and regular-expression matching for terms
  • Case and accent folding
  • COUNT(*) queries and BM25-scored top-k queries

A good text index in Postgres must support all of those things while also handling joins, complicated WHERE clauses across full-text and other column types, continuous updates, replication, backups, and correct transaction visibility.

Although there are at least three existing text-search indexes for Postgres already, none of them met all of those requirements. TIN does. TIN is also really, mind-blowingly fast.

TIN performance and benchmarking

We ran benchmarks to assess performance for all the above use cases and more. Benchmark results on an 85 GB Stack Exchange corpus (150 million documents):

Index build time and size

Total timeIndex sizeRequired RAM
TIN8m10s50.7 GB32 GB
ParadeDB19m20s52.1 GB64 GB
pg_textsearch26m49s41.5 GB128 GB
Postgres GIN2h09m04s28.0 GB64 GB

Mixed queries, top-10 ranked

TIN handles 25× as many queries per second as ParadeDB does, with p99 latencies 26× lower. GIN can’t complete this benchmark, because it runs out of memory performing the disjunction searches.

Conjunction and phrase queries, top-10 ranked

TIN handles 10× as many queries as ParadeDB and 541× as many as GIN, with p99 latencies 6× and 1,356× lower, respectively.

Disjunction queries with concurrent writes

TIN handles 36× as many queries as pg_textsearch and 57× as many queries as ParadeDB, with p99 latencies 24× and 36× lower, respectively. Over the course of a ten-minute run, TIN completes 270,279 updates, while ParadeDB completes 185,584, and pg_textsearch completes only 735.

When the index fits in memory

On Wikipedia (8.0 GB corpus), TIN achieved 10,260 QPS on disjunction COUNT queries vs ParadeDB’s 291 and GIN’s 1.4.

Why TIN is fast

TIN directly uses Postgres’ ctid value as a document identifier rather than sequential document IDs. This avoids remapping overhead, enables two-level bitmap encoding for 48-bit identifiers, supports vectorized intersection/union on AVX2/AVX-512, and integrates with Postgres MVCC and visibility maps.

TIN returns MVCC-correct results, supports index-only scans when pages are all-visible, and maintains per-segment liveness bitmaps updated by VACUUM.

Segment merging reuses bitmaps without renumbering document IDs, reducing write amplification compared to traditional text indexes.

Summary

TIN is at least 8× faster in every benchmark scenario tested, driven by using ctid as the native format for each posting in the index.