PlanetScale launches TIN to put full-text search inside Postgres

PlanetScale's GA extension supports BM25, phrase, and fuzzy search; its company-run benchmarks report large gains over rival indexes.

By · Published

Primary source: PlanetScale

Why it matters

TIN expands PlanetScale's Postgres offering into application search, giving developers a way to keep search queries, transactions and backups in one database. Lead provides a compatible, deliberately slow substitute for local development, CI and staging.

A developer types on a laptop displaying database code, with a PlanetScale water bottle on a desk and a blurred background hinting at a data network.

PlanetScale contributors Eric Ridge and Patrick Reynolds (@p_reynolds) launched TIN, a full-text search extension for Postgres, on September 16th. TIN runs inside the database, supports BM25 ranking and becomes searchable as soon as a transaction commits. PlanetScale made it generally available across its Postgres and Neki products.

The product puts Reynolds back on familiar ground. Before joining PlanetScale, he was a distinguished engineer at GitHub, where he founded the Blackbird code-search project, co-founded GitHub Actions and built systems that stored GitHub's repositories. His personal biography traces a career through distributed systems, performance debugging and peer-to-peer keyword search. TIN applies that search background to a commercial problem PlanetScale keeps encountering: application developers want capable search without operating another data system beside Postgres.

That goal also fits the architecture-first playbook PlanetScale inherited from founders Jiten Vaidya and Sugu Sougoumarane. The pair created Vitess at YouTube to scale MySQL, then founded PlanetScale to turn those techniques into a managed database service. PlanetScale is now applying the same philosophy to Postgres: make the database handle workloads that usually force developers to assemble extra infrastructure.

Search stays beside the transactions

Developers create a TIN index with ordinary-looking Postgres syntax:

CREATE INDEX posts_body_tin ON posts USING tin(body);

Queries use PlanetScale's ==> operator. TIN supports Boolean, phrase and span searches, along with fuzzy terms, wildcards, regular expressions, case folding and accent folding. It can return exact counts or rank results using BM25, the relevance-scoring method widely used by modern search engines.

The operational pitch carries as much weight as the query syntax. Search results remain subject to Postgres transaction visibility, and TIN works with joins, ordinary WHERE conditions, replication, backups and continuous updates. An application can search a newly committed row without waiting for data to move into a separate Elasticsearch or OpenSearch cluster.

PlanetScale's TIN documentation says each index covers one text column or expression. Developers can combine indexes across fields, boost individual fields and use Postgres partial or expression indexes. The default tokenizer folds case and accents and indexes emoji as searchable terms.

PlanetScale's benchmark is large and still vendor-run

PlanetScale tested TIN 1.0.2 against ParadeDB 0.25.2, Tiger Data's pg_textsearch 1.4.0 and the GIN index included with Postgres 18.6. The test used an 85 GB Stack Exchange corpus containing 150 million documents and 1,719 synthetic queries generated from substrings of two to 15 terms.

The systems ran sequentially on an AWS i7i.8xlarge instance. Each query container was limited to eight virtual CPUs and 32 GB of RAM. PlanetScale increased memory during index construction for the three competing systems after they failed under the 32 GB limit, then returned every system to 32 GB for query testing.

TIN built its 50.7 GB index in 8 minutes and 10 seconds, according to PlanetScale's announcement. ParadeDB took 19 minutes and 20 seconds to build a 52.1 GB index. Pg_textsearch took 26 minutes and 49 seconds, while Postgres GIN took 2 hours, 9 minutes and 4 seconds.

In the mixed top-10 workload, PlanetScale reported 199 queries per second for TIN and 7.9 for ParadeDB, a roughly 25x difference. PlanetScale also reported 26x lower p99 latency. In a conjunction-and-phrase workload, TIN delivered 242 queries per second, compared with 24 for ParadeDB and 0.4 for GIN.

Those ratios come from PlanetScale's own test design, synthetic query set and isolated hardware. Only TIN and ParadeDB completed every workload. GIN and pg_textsearch were absent from some comparisons because they ran out of memory or did not support the query shape. Developers evaluating TIN should rerun the work against their own documents, ranking requirements and update patterns before treating the headline multipliers as purchasing criteria.

The caveat has become familiar in PlanetScale's recent product campaign. On September 11th, RuntimeWire examined PlanetScale's 118 million-query-per-second Neki test, which showed clean horizontal scaling while leaving out writes, joins, replicas and failover. TIN's test covers a wider mix of reads and concurrent updates, though PlanetScale still controlled the corpus, configuration and comparison.

The speed comes from speaking Postgres directly

TIN's central technical choice is to use Postgres ctid values as document identifiers. A ctid points to the physical location of a row version inside a Postgres heap. Search systems that assign their own sequential document IDs eventually need to map those IDs back to ctid values before Postgres can retrieve rows.

TIN avoids that mapping layer. PlanetScale encodes page numbers and tuple offsets in two-level bitmaps, then uses CPU vector instructions to intersect or combine them. The same representation helps TIN process counts, retrieve matching rows in heap order and work with Postgres visibility maps.

The design also reduces work when index segments merge. Since a ctid retains the same meaning across segments, TIN does not need to renumber every document and rewrite the entire combined index. PlanetScale attributes TIN's benchmark advantage to the downstream effects of that decision.

TIN enters an active category. ParadeDB's pg_search adds BM25 search through a Postgres extension powered by Tantivy, while Tiger Data's pg_textsearch implements a BM25 index using Postgres storage. Built-in GIN remains available without adding a third-party search extension, though its ranking and supported workloads differ from TIN's.

TIN is GA for PlanetScale Postgres and Neki, with Lead for development and CI

PlanetScale documents TIN for production search on its Postgres and Neki products. For local development, continuous integration and staging, Ridge and Reynolds released Lead, an AGPL-licensed extension that accepts TIN-compatible SQL and produces correct results while deliberately avoiding a production search index.

Lead scans every table page and lets Postgres recheck visible rows. Its repository describes the implementation as intentionally unsuitable for production workloads. PlanetScale recommends it for small development and test datasets, giving teams a way to exercise the same ==> operator, TINQL syntax and scoring functions without connecting a test database to PlanetScale.

The two extensions support a common application workflow: developers can keep search logic in SQL, run compatible tests locally or in CI and use TIN for production search on PlanetScale Postgres or Neki. PlanetScale's materials do not establish whether TIN can be installed independently outside those products.

For Ridge and Reynolds, the wager is straightforward: enough developers would prefer search as a database primitive, provided it behaves like Postgres and survives production write traffic. PlanetScale has supplied an ambitious benchmark and a detailed architectural explanation. Real application corpora will decide how much of the claimed advantage survives contact with product catalogs, support archives and other messy text.

Reader comments

Conversation for this story loads after sign-in.