# How I added search to my static site with Pagefind

> 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.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-07-06 | Topics: [Astro](https://flaviocopes.com/tags/astro/) | Canonical: https://flaviocopes.com/static-site-search-pagefind/

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](https://pagefind.app) 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:

```bash
npm install -D pagefind
```

Then run it after your build, pointing it at your output folder. On my [Astro](https://flaviocopes.com/astro-introduction/) site the output is `dist`:

```json
{
  "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:

```html
<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:

```html
<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:

```bash
npm run build
npm run preview
```

That's the whole setup, and it costs nothing to run.
