graft. docs

Search

Full-text search on the content index and on operational data, on either tier.

Search is a property of the index. It comes with the compile, on both tiers, with no app-side bookkeeping and nothing extra to run.

One API covers both. The engine underneath differs, the call and the query syntax do not.

Static indexPostgres
EngineSQLite FTS5, porter stemmingGenerated tsvector columns, GIN
Rankingbm25 with column weightsts_rank over a weighted vector
Weightingslug > frontmatter strings > bodyslug (A) > frontmatter strings (B) > body (C)
Needsnothinga database

The static tier translates the same websearch surface into an FTS5 MATCH expression, and its bm25 column weights mirror the Postgres A/B/C vector, so results come back in the same order for the same query.

Authored content

Surfaces:

SurfaceCall
SDKgraft.searchContent(collection, query)
MCPsearch_content
dbsearchContent (used under the hood)

Query syntax is the websearch_to_tsquery surface: words, "quoted phrases", or, and -exclusions. Empty queries fail with INPUT_VALIDATION_FAILED. Stopword-only queries return [].

Hits include rank, headline snippets, and sourcePath (the file to edit). On overlay branches, search walks the branch chain so inherited documents appear.

Snippets mark the matched terms with <b> on both tiers. Render them or strip them, but know they are there.

Operational data

Data search stays behind typed functions (searchRecords in core). The same authority and Zod rules apply as to other record helpers. Example apps expose gated functions such as searchSubmissions.

Operational data is Postgres-tier by construction, so this half has no static equivalent. Calling it in static mode fails with NEEDS_DATABASE.

Language

The FTS config is English on both tiers: 'english' on Postgres, porter unicode61 on FTS5. Per-collection language configs are an open follow-up.