How to build this blog
This post walks through how this very blog is built: an Astro content site with Pagefind for static, client-side full-text search.
What you get
- An Astro 6 content collection for posts authored in Markdown or MDX.
- A production build that emits a static search index alongside the HTML.
- A
/searchpage powered by the Pagefind UI — no server, no API key, no third-party dependency at runtime.
1. Scaffold the Astro blog
Start from the official starter:
npm create astro@latest -- --template blog
cd my-blog
npm install
That gives you the content collection in src/content/blog/, a BlogPost layout, and routes for /, /blog, /blog/[slug], and /about.
2. Add Pagefind
Install Pagefind as a dev dependency and chain it onto the build script in package.json:
{
"scripts": {
"build": "astro build && pagefind --site dist"
},
"devDependencies": {
"pagefind": "^1.4.0"
}
}
Pagefind walks the built dist/ directory, parses the HTML, and writes a static index to dist/pagefind/. No config file is required for the default setup.
3. Tell Pagefind what to index
By default Pagefind indexes the entire <body> of every page. To restrict indexing to post content (and skip the header/footer), add data-pagefind-body to the <article> in src/layouts/BlogPost.astro:
<main>
<article data-pagefind-body>
{/* hero image, title, slot... */}
</article>
</main>
Once any page on the site uses data-pagefind-body, Pagefind switches modes and only indexes pages that opt in.
4. Build a Search component
Pagefind ships a default UI bundle. Load it on demand from a small Astro component so it isn’t pulled into every page:
---
const { id = 'search' } = Astro.props;
---
<link rel="stylesheet" href="/pagefind/pagefind-ui.css" />
<div id={id}></div>
<script is:inline define:vars={{ id }}>
window.addEventListener('DOMContentLoaded', () => {
const script = document.createElement('script');
script.src = '/pagefind/pagefind-ui.js';
script.onload = () => new window.PagefindUI({ element: `#${id}` });
document.head.appendChild(script);
});
</script>
Then drop it onto a dedicated route at src/pages/search.astro and link to /search from the header.
5. Build and preview
npm run build
npm run preview
Open /search and start typing — results stream in from the static index. Because Pagefind only generates its index during astro build, search will be unavailable under astro dev; the component above shows a friendly placeholder in that case.
What about scaling?
Pagefind chunks its index by language and lazy-loads only the shards needed for a given query, so a blog with thousands of posts still ships kilobytes of JS to the user up front. For most personal sites you can ignore the index size entirely.
More
- Pagefind documentation
- Astro content collections
- The
data-pagefind-*attributes for finer control over what gets indexed.