Static sites lack a backend database to power traditional search, but client-side search — using a pre-built search index loaded in the browser — provides fast, genuinely useful search without needing any server-side search infrastructure.
Why Client-Side Search Works Well for Static Sites
For sites of reasonable size (hundreds to a few thousand pages), a search index can be pre-built at build time and loaded entirely in the browser — search then happens instantly, client-side, without any server round-trip, fitting naturally with static hosting's architecture.
Using Lunr.js for Client-Side Search
npm install lunr
const lunr = require('lunr');
const idx = lunr(function () {
this.field('title');
this.field('content');
documents.forEach((doc) => this.add(doc));
});
fs.writeFileSync('search-index.json', JSON.stringify(idx));
Build the search index as part of your static site build process (see How to Set Up Automatic Static Site Deployment from Git), generating a JSON index file deployed alongside your site.
Loading and Querying the Index Client-Side
fetch('/search-index.json')
.then(res => res.json())
.then(idx => {
const searchIndex = lunr.Index.load(idx);
document.getElementById('search').addEventListener('input', (e) => {
const results = searchIndex.search(e.target.value);
displayResults(results);
});
});
Alternative: Using Pagefind (Purpose-Built for Static Sites)
npx pagefind --site dist
Pagefind automatically indexes your built static site's HTML content directly, requiring less manual index-building setup than Lunr.js — a strong, increasingly popular option specifically designed for static site search use cases.
Considering Index Size for Larger Sites
A full-text search index can become large for sites with extensive content — for very large sites, consider indexing only titles/summaries rather than full content, or splitting the index and loading it incrementally, to avoid an unreasonably large initial download.
Handling Search Result Presentation
function displayResults(results) {
const container = document.getElementById('results');
container.innerHTML = results.map(r =>
`<a href="${r.ref}">${documents.find(d => d.id === r.ref).title}</a>`
).join('');
}
Adding Search Highlighting
Consider highlighting matched terms within result snippets — improves user experience by showing exactly why a result matched, though requires slightly more sophisticated result rendering than a plain title/link list.
Testing Search Relevance
Try realistic search queries your actual users might use, not just exact title matches — verify results are genuinely relevant and reasonably ordered; tune indexing configuration (field weighting, stemming) if results feel off.
Comparing to a Hosted Search Service
For very large sites or more sophisticated search needs (typo tolerance, faceted search), a dedicated hosted search service is an alternative to self-built client-side search — weigh the trade-off between self-hosted simplicity/cost and a managed service's more advanced capabilities for your specific scale.
Common Errors
Search index build fails or produces empty results — verify your build process correctly captures all content you intend to index, and check that the index-building step runs after content generation, not before, in your build pipeline order.
Continue Reading
- How to Set Up Automatic Static Site Deployment from Git
- How to Optimize JavaScript Bundle Size for Faster Page Loads
- Choosing Between Static Site Hosting and a Traditional Server
Browse more articles in Static Site Hosting & Frontend Deployment.