Building static full-text search without Lunr or Pagefind
2026-01-18 · Finn O'Brien
Adding full-text search to a static site generator without pulling in a JavaScript framework is a fun constraint. Here's the approach StoneBark 1.0 uses.
Build-time index
At build time, StoneBark reads every page, strips HTML tags, tokenises the text, and builds an inverted index: a map from term to the list of (document, position) pairs where it appears. This is written as a single JSON file, search-index.json, alongside the rest of the site output.
The index includes stemmed terms (using a simple Porter stemmer for English) alongside the raw terms, so searching for "rendering" also finds "rendered" and "renders".
The frontend
The search frontend is about 80 lines of vanilla JavaScript embedded directly in the default theme's base.html. It fetches the index file on first keypress (not on page load), caches it in a module variable, and queries it synchronously. No web workers, no IndexedDB.
Performance is acceptable for sites up to about 500 pages. Beyond that the index gets large enough to warrant a more sophisticated approach, which is outside StoneBark's intended scope.
Why not Pagefind
Pagefind is excellent and I'd recommend it for large sites. For small sites it requires a post-processing step that complicates the build pipeline, and it brings in a WASM binary dependency. StoneBark's search is intentionally less capable but requires nothing beyond what stonebark build already produces.