Static site search for Astro in 2026: why I picked Pagefind over Algolia and Lunr

Static site search for Astro in 2026: why I picked Pagefind over Algolia and Lunr

2026 年 Astro 静态站点搜索:为什么我选择了 Pagefind 而非 Algolia 和 Lunr

I added search to all three of my AI-curated directory sites last month. The choice wasn’t obvious — there are at least four options with real adoption — so here’s the breakdown I actually ran through before landing on Pagefind. 上个月,我为我所有的三个 AI 策展目录网站添加了搜索功能。这个选择并不简单——目前至少有四种方案被广泛采用——因此,以下是我在最终决定使用 Pagefind 之前所做的详细分析。

The four options I considered

我考虑的四种方案

Pagefind is a Rust-based static search library. It runs at build time, generates an index in /_pagefind/, and serves everything as static files. No backend, no API key, no per-query billing. It ships a prebuilt UI (PagefindUI) that you can mount on any element, and it supports WebAssembly for in-browser querying. Pagefind 是一个基于 Rust 的静态搜索库。它在构建时运行,在 /_pagefind/ 目录下生成索引,并将所有内容作为静态文件提供。它不需要后端、API 密钥,也没有按查询计费。它提供了一个预构建的 UI (PagefindUI),你可以将其挂载到任何元素上,并支持通过 WebAssembly 在浏览器内进行查询。

Algolia DocSearch is free for open-source documentation sites, $49/month for commercial sites below a certain crawl limit. It indexes your content via their crawler (or an API push), stores it on Algolia’s infrastructure, and gives you a hosted search widget. Fast, polished, and battle-tested — it’s what most major docs sites use. Algolia DocSearch 对开源文档网站免费,对于低于特定抓取限制的商业网站,费用为每月 49 美元。它通过其爬虫(或 API 推送)索引你的内容,将其存储在 Algolia 的基础设施上,并为你提供一个托管的搜索小部件。它快速、精致且经过实战检验——这是大多数主流文档网站的选择。

Lunr.js is a client-side search library. You build the index at build time, serialize it to JSON, and ship it with the page. The browser loads the entire index on first search. Works offline, no external dependency, but the index size grows linearly with content, and there’s no incremental loading. Lunr.js 是一个客户端搜索库。你在构建时生成索引,将其序列化为 JSON,并随页面一起发布。浏览器在首次搜索时会加载整个索引。它支持离线工作,没有外部依赖,但索引大小随内容线性增长,且不支持增量加载。

FlexSearch is a newer alternative to Lunr with better performance characteristics and smaller bundle size, but the same core trade-off: you ship the whole index to the browser upfront. FlexSearch 是 Lunr 的一个较新的替代方案,具有更好的性能表现和更小的包体积,但存在同样的核心权衡:你需要预先将整个索引发送到浏览器。

Why Pagefind won

为什么 Pagefind 胜出

The decisive factor was index size management. My directories have 500-1,000 entries per site, each with a multi-paragraph generated description. A Lunr index for 1,000 entries would be 2-4MB shipped with every page load. Pagefind shards its index and loads chunks lazily as the user types — so the initial load is under 30KB (the WASM binary + a small manifest), and individual chunk fetches happen on demand. 决定性因素是索引大小的管理。我的每个目录网站有 500 到 1,000 个条目,每个条目都有多段生成的描述。对于 1,000 个条目,Lunr 的索引大小将达到 2-4MB,且每次页面加载都需要下载。Pagefind 对索引进行了分片,并随着用户的输入懒加载数据块——因此初始加载量不到 30KB(WASM 二进制文件 + 一个小的清单文件),后续的数据块按需获取。

The second factor was cost. Algolia DocSearch’s commercial tier runs $49/month per site. I’m running three sites on a total infrastructure budget of roughly $25/month. Pagefind is free. 第二个因素是成本。Algolia DocSearch 的商业版每个站点每月收费 49 美元。我运营三个网站的总基础设施预算大约是每月 25 美元。而 Pagefind 是免费的。

The third factor was the deploy model. Because everything in /_pagefind/ is a static file, Cloudflare Pages caches it at the edge with no configuration. There’s no API to rate-limit, no service availability to depend on, no API key to rotate. 第三个因素是部署模式。由于 /_pagefind/ 中的所有内容都是静态文件,Cloudflare Pages 无需任何配置即可在边缘节点缓存它们。没有需要限流的 API,不依赖服务可用性,也不需要轮换 API 密钥。

The SearchDialog implementation

SearchDialog 的实现

The search component is a <dialog> element with a Pagefind UI mounted inside it. I load the pagefind-ui.js script lazily — only when the dialog is first opened — to keep it off the critical path: 搜索组件是一个 <dialog> 元素,内部挂载了 Pagefind UI。我采用懒加载方式加载 pagefind-ui.js 脚本——仅在对话框首次打开时加载——以避免阻塞关键路径:

function loadPagefind() {
  if (loaded || !root) return;
  loaded = true;
  var s = document.createElement("script");
  s.src = "/_pagefind/pagefind-ui.js";
  s.onload = function () {
    if (window.PagefindUI) {
      new window.PagefindUI({ element: root, showSubResults: true, resetStyles: false });
    }
  };
  s.onerror = function () {
    root.innerHTML = '<p>Search index not available yet (first build). Try again after next deploy.</p>';
  };
  document.head.appendChild(s);
}

The s.onerror handler is the part most tutorials skip. On the first deploy of a new Cloudflare Pages site, the /_pagefind/ directory doesn’t exist yet — Pagefind only runs during the build. If a user opens search before the first full build completes, pagefind-ui.js 404s. Without the error handler, you get a silent failure. With it, you get a legible message. s.onerror 处理程序是大多数教程忽略的部分。在 Cloudflare Pages 网站的首次部署中,/_pagefind/ 目录尚不存在——Pagefind 仅在构建期间运行。如果用户在首次完整构建完成前打开搜索,pagefind-ui.js 会报 404 错误。如果没有错误处理程序,你会遇到静默失败;有了它,用户就能看到清晰的提示信息。

The <dialog> element is the right primitive here: it handles focus trapping automatically, Escape closes it natively, and backdrop:: CSS pseudo-element gives you the dimmed overlay without JavaScript. The Cmd+K keyboard shortcut is wired with document.addEventListener("keydown", ...) — no library needed. <dialog> 元素是这里的最佳选择:它自动处理焦点锁定,按 Escape 键可原生关闭,且 backdrop:: CSS 伪元素无需 JavaScript 即可实现遮罩层效果。Cmd+K 快捷键通过 document.addEventListener("keydown", ...) 绑定——无需任何库。

What Pagefind doesn’t do

Pagefind 的局限性

Two gaps I’ve hit: 我遇到的两个不足之处:

  1. No query logging. Pagefind runs entirely in the browser and doesn’t send queries anywhere. For a commercial directory, knowing what users search for is valuable — it tells you which models or games to add, and which compare pages to prioritize. With Algolia you get this for free. With Pagefind you’d need to add a thin logging layer (a fetch POST to an analytics endpoint on each query event). I haven’t built this yet.

  2. 没有查询日志。 Pagefind 完全在浏览器中运行,不会向任何地方发送查询数据。对于商业目录,了解用户搜索的内容非常有价值——它能告诉你该添加哪些模型或游戏,以及优先优化哪些对比页面。使用 Algolia 可以免费获得此功能。而使用 Pagefind,你需要添加一个轻量级的日志层(在每次查询事件时向分析端点发送 fetch POST 请求)。我目前还没做这个。

  3. No fuzzy matching out of the box. Pagefind does stemming and basic substring matching, but “stabilty diffusion” (typo) won’t match “stable diffusion”. Algolia’s typo-tolerance is significantly better. For an AI tools directory where model names are long and often misremembered, this matters. I’ll probably add a query-suggestion layer that does fuzzy pre-matching before handing off to Pagefind.

  4. 没有开箱即用的模糊匹配。 Pagefind 支持词干提取和基本的子字符串匹配,但“stabilty diffusion”(拼写错误)无法匹配到“stable diffusion”。Algolia 的容错能力要好得多。对于模型名称较长且容易记错的 AI 工具目录来说,这一点很重要。我可能会添加一个查询建议层,在交给 Pagefind 之前进行模糊预匹配。

Quick comparison table

快速对比表

FeaturePagefindAlgolia DocSearchLunr.js
CostFree$49/mo (commercial)Free
Index locationStatic filesAlgolia cloudShipped with page
Initial JS load~30KB~80KB~10KB + index
Index size scalabilityChunked, lazyServer-sideLinear, upfront
Typo toleranceBasic stemmingStrongWeak
Query loggingNoYesNo
Build-time integrationYesCrawler / push APIYes
特性PagefindAlgolia DocSearchLunr.js
成本免费$49/月 (商业)免费
索引位置静态文件Algolia 云端随页面发布
初始 JS 加载~30KB~80KB~10KB + 索引
索引扩展性分块、懒加载服务端处理线性、预加载
容错能力基本词干提取
查询日志
构建集成爬虫 / API 推送

For a static site on a tight infrastructure budget with 500-1,000 entries, Pagefind is the right default. If the site were larger or if I needed typo tolerance and query analytics without building them myself, Algolia would be worth the cost. 对于预算紧张、拥有 500-1,000 个条目的静态站点,Pagefind 是首选方案。如果站点规模更大,或者我需要容错和查询分析功能且不想自己开发,那么 Algolia 的成本是值得的。

Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted. 这是我正在进行的三个 AI 策展目录网站 6 个月实验的一部分。文中的技术主张均为真实情况;本文由 AI 辅助撰写。