Pagefind vs Meilisearch for a Static Docs Site: When You Don’t Want Another Daemon

Elena Varga

Elena Varga

August 25, 2026

Pagefind vs Meilisearch for a Static Docs Site: When You Don't Want Another Daemon

I added Meilisearch to a documentation site that had 180 pages and a deploy pipeline that already took four minutes. If you are still choosing a search daemon at all, start with Meilisearch versus Elasticsearch or the even smaller SQLite FTS5 fork. Search got better. The ops list got longer: a container, a volume, an API key in CI, a backup I pretended I would test, and a 3 a.m. page because the daemon was up and the index was empty after a disk fill.

Pagefind is the rude answer. It is not a search engine you run. It is a build step that writes a pile of static files and a WASM client. The site you already know how to host becomes the search host. That is either a relief or a cop-out, depending on whether your users type like humans or like a faceted catalog.

What a docs site actually queries

Most documentation search is “where is the healthcheck example” and “what is start_period.” It is not “show me SKUs in stock between $12 and $40 with a 4-star rating.” If your docs search looks like an e-commerce facet panel, you do not have a docs site. You have an app with a docs skin.

Pagefind is built for the first case. It crawls the HTML you already emit, chunks it, and lets the browser download only the shards it needs for the query. There is no query language to protect. There is no API key to leak in a screenshot. The worst leak is that your search index is public, which your documentation already was.

Meilisearch is built for the second case and happens to work for the first. Typo tolerance is excellent. Filters and ranking rules are real. You can keep drafts out of the public index. You can update one page without rebuilding the world. You can also spend a Saturday deciding whether the master key lives in Docker secrets or in a file you will commit by accident.

The daemon you did not want

A static docs site is usually Cloudflare Pages, Netlify, GitHub Pages, or a Caddy file server on a VPS that already runs two other things. Adding Meilisearch means adding a process that must be up whenever a reader searches. That is a new availability story. Your HTML can be a CDN edge cache. Your search box now needs origin.

People paper over this with Meilisearch Cloud or a tiny VM. Both are fine. Both are another bill and another dashboard. I have seen a docs site go down for search while the pages themselves were fine, because the Compose healthcheck passed and the index was still loading. Readers do not file a nuanced ticket. They say search is broken.

Pagefind fails like a static asset. If the shard 404s, one query fails. The rest of the site is untouched. You debug it the way you debug a missing CSS file. That is a failure mode I can explain to a future maintainer in one sentence.

Hands writing in a notebook beside a laptop showing documentation

Build time versus query quality

Pagefind adds a step after your static generator. On 180 pages it is cheap. On a few thousand HTML files it is still cheaper than you fear, but the index artifacts become a deploy-size conversation. You will notice the extra files in the publish directory. You will not notice a Rust process holding RAM on the server, because there is not one.

Relevance is good enough for prose. It is not Meilisearch. Typos like “healtcheck” still work more often than a naive grep, less often than Meili’s default ranking. If your users are developers, they type closer to the identifier. If your users are tired operators on a phone, Meili’s tolerance is a feature you can feel.

I ran the same ten queries against both on a Compose-docs clone. Exact terms were a wash. Two-character typos and “almost the heading” queries belonged to Meilisearch. “Healthcheck start_period” belonged to whoever indexed the heading as a heading. Pagefind’s heading boost is not a ranking DSL. Meili’s is. If you want to say “title is worth 10, body is worth 1,” you want Meili.

Updates, previews, and the PR preview tax

Static hosts love pull-request previews. Pagefind loves them too: the preview deploy has its own index, generated from that branch’s HTML. Search matches the draft. That is the correct behavior for docs.

Meilisearch on preview deploys is a small nightmare. One shared instance means preview content leaks into production search, or you build a per-preview index and a cleanup job. Per-preview Meili instances are how a solo maintainer learns to hate review apps. I have done the “one index, filter on env” trick. I have also indexed a draft security advisory into production search on a Friday. Pagefind would have kept that draft on the preview URL.

The other direction is instant edits. A community member fixes a typo in a page. With Meili you can re-index that document from CI without a full static rebuild — if your pipeline is set up that way. Most docs pipelines rebuild the site anyway. The extra Meili step is then just another place to fail.

A quiet home office at dusk with a terminal on the monitor

When Meilisearch is still the right daemon

Keep Meili if the docs are a slice of a product that already runs it. One cluster, one set of keys, docs as an index next to the in-app help. The daemon is not “another” daemon. It is the one you have.

Keep Meili if you need:

  • Faceted navigation (version, product, language) that is not “a different static site.”
  • Search across docs plus a knowledge base plus GitHub issues you ingest on a schedule.
  • Authenticated search, or a mix of public and private pages that must not share an index file on a CDN.
  • Typo tolerance that is part of the product promise, not a nice extra on a reference manual.

A multi-version docs site can go either way. Separate Pagefind indexes per version, or one Meili index with a version filter. The first is more files. The second is more process. I pick files until the filter UI is the product.

Security and the public index

Pagefind’s index is downloadable. Anyone can fetch shards. That is the same class of problem as “view source.” If a page should not be searchable, it should not be in the public HTML you crawl. Exclude paths. Do not put a staging note in a noindex page and assume Pagefind will be wiser than your generator.

Meilisearch can require a search API key. The key still ends up in the frontend for a public docs site, so the protection is rate limits and a smaller attack surface, not secrecy. For private docs behind login, Meili (or a server-side proxy) is the tool. Pagefind on a private static site only works if the whole site, index included, is behind the same auth. That is doable with Caddy + basic auth. It is clumsy with a CDN that caches anonymously.

Index size, phones, and the first-keystroke wait

Pagefind’s pitch includes “only download the shards you need.” That is true after the WASM runtime is cached. The first search on a cold phone still pays for the client and the first shard. On a desktop with a warm CDN cache I do not notice. On a mid-range Android on hotel Wi-Fi I notice the pause before the first result. Meilisearch’s first keystroke is a tiny HTTP request. The runtime cost lives on your server. That is the old trade: move CPU to the reader, or keep CPU in the daemon.

Index bytes on disk are the other surprise. A docs site with lots of repeated chrome — the same sidebar text in every HTML file — can bloat a naive crawl. Pagefind is not naive, but if you forget to exclude nav and footer, you will search the word “Pricing” on every page. Meili has the same problem if you send it full HTML. The fix in both cases is to index the article body, not the chrome. Pagefind wants CSS selectors. Meili wants you to send clean JSON from the generator. I prefer selectors until the generator already has a search export.

Offline is the sleeper feature. A Pagefind site in a service worker can search on a plane. A Meili box cannot. If your readers are the kind of people who download docs before a site visit, that is not theoretical. I have used the airplane test as a tie-breaker twice. Both times Pagefind won, and both times the site was a manual, not a store.

What I run now

The 180-page site is on Pagefind. Search is a box at the top. CI runs pagefind --site dist and uploads dist. I deleted the Meili service, the volume, and the “search is degraded” status component. The remaining search bugs are “this page used a client-rendered heading that Pagefind never saw.” That is a static-site bug. I fix the HTML.

The indie app that already had Meilisearch still uses it for in-app search and a small help center. I did not add a second search product. Two indexes in one daemon beat a daemon plus a WASM index plus a story about why they rank differently.

A decision you can write on a sticky note

If the site is HTML you already deploy, and search is “find the page,” use Pagefind. If search is a feature with filters, auth, or a process you already babysit, use Meilisearch. If you are adding Meili only because a blog post said indie apps need a search engine, you are about to own a daemon whose only job is to find a heading that was already in the sitemap.

I like Meilisearch. I like it more when it is not glued to a site that could have been a folder of files. The first time search is “down” while the docs are up, you will remember this paragraph.

More articles for you