How I added search to my static site with Pagefind
By Flavio Copes
How I added fast client-side search to my static Astro blog with Pagefind, which indexes your HTML at build time and runs entirely in the browser.
This blog has over 1700 posts and, until recently, no search.
The problem with search on a static site is that there’s no server to run the query. I didn’t want to add a backend, or pay for a hosted search service, just for this.
Pagefind solves it. It indexes your HTML after the build, and the search runs entirely in the browser.
How Pagefind works
You build your site as usual. Then Pagefind reads the generated HTML and builds a search index, split into small chunks.
When someone searches, the browser downloads only the chunks it needs. So even with thousands of pages, a visitor downloads a few kilobytes, not the whole index.
No server. No database. No monthly bill.
Installing it
Install Pagefind as a dev dependency:
npm install -D pagefind
Then run it after your build, pointing it at your output folder. On my Astro site the output is dist:
{
"scripts": {
"build": "astro build && pagefind --site dist"
}
}
Now every build creates a dist/pagefind/ folder with the index and a ready-made search UI.
Adding the search box
Pagefind ships a UI you can drop in. I made a /search page with an empty container and loaded the UI into it:
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
<div id="search"></div>
<script src="/pagefind/pagefind-ui.js"></script>
<script>
window.addEventListener('DOMContentLoaded', () => {
new PagefindUI({ element: '#search' })
})
</script>
That’s a full search page. Type a word and results show up as you type.
Searching only your content
By default Pagefind indexes the whole page, including your header and footer. That’s noisy: every page ends up matching the words in your nav.
The fix is one attribute. Add data-pagefind-body to the element that holds your actual content:
<article data-pagefind-body>
<!-- the post -->
</article>
Once any page uses data-pagefind-body, Pagefind only indexes those regions, and skips pages that don’t have it. So my search returns posts, not menu items.
One thing to watch
Pagefind runs on the built site, so it doesn’t work in the dev server. The index doesn’t exist until you build.
To test it locally, build first, then preview:
npm run build
npm run preview
That’s the whole setup, and it costs nothing to run.
Related posts about astro: