Skip to main content
Pylon ships a built-in, faceted full-text search layer. Add a search: block to an entity to get BM25 ranking, live facet counts, and sort across millions of rows, with no separate search server such as Meilisearch or Elasticsearch. The index lives inside the same SQLite or Postgres database, in the same transaction as your writes.

Declaring a searchable entity

On schema push, Pylon creates an FTS5 shadow table and a roaring-bitmap facet index. Every insert, update, and delete maintains both inside the same transaction as the row write, so the index does not lag behind the row.

Searching from the client

db.useSearch is the React hook. It returns ranked hits, per-facet counts, a total, and timing.
The hook re-runs automatically when matching rows in the entity change, so facet counts and result lists stay synchronized with writes. It needs no manual invalidation and no refetch button.

Searching from a server function

The same query shape works server-side via ctx.db.search. Use it when you need to search inside a transaction or pre-aggregate before returning.

How it works

  • Text matching: SQLite FTS5 or Postgres tsvector, with BM25 ranking by default, configurable per field.
  • Facets: roaring bitmaps stored in a _facet_bitmap table, one bitmap per (entity, column, value). Intersection across active filters is bit-AND, which is faster than WHERE clauses by 10–100× at scale.
  • Sort and paginate: when the planner needs to sort across the entire match set, it materializes hit ids into a temporary table, joins back to the row table, and applies ORDER BY together with LIMIT and OFFSET. This is the only way to paginate consistently across a sorted projection.
  • Aggregation safety: faceted search refuses to run on entities whose read policy depends on per-row data. Otherwise, facet counts would leak the existence of rows the caller cannot read. To opt in, make your read policy row-independent (for example, auth.userId != null), or scope reads with a server function.

API

POST /api/search/:entity accepts:
Returns:

Performance

Native search trades the operational cost of a separate index server for slightly higher per-query latency on very large datasets (over 10 million rows). For many B2B SaaS workloads, it is faster overall: no network hop, no asynchronous indexing lag, and no second system to monitor. The examples/store example runs a 10,000-product catalog with 3-facet search at sub-5ms p95 on a $5 VPS.

Next

Faceted search example

Walk through the store with code highlights.

Live queries

How search results stay up to date.