Troubleshooting·6 min read·

Why is search returning no results?

Pagefind index stale or missing, postbuild step skipped, SSG not building help articles, and static export config — fix the VeloCMS help search when it returns empty.

You type a keyword into the VeloCMS help search bar and nothing comes back — or only a handful of results show up when you know there should be dozens. Search on VeloCMS is powered by Pagefind, a static-site search library that indexes your content at build time. When search breaks, it's almost always a build-time problem, not a runtime one.

How Pagefind works in VeloCMS

During the npm run build step, Next.js generates static HTML files for every help article route (/help/[slug]). After that generation, a postbuild script runs Pagefind against the .next/server/app directory and writes a search index to public/pagefind/. This index is served as a static asset alongside the site. When a user searches, the browser downloads the index and performs the lookup entirely client-side — no server query happens.

The index is missing entirely

If the search returns no results at all (even for very common words), the most likely cause is that the Pagefind index doesn't exist. This happens when the postbuild step was skipped — for example if npm run build was interrupted, or if you're running the dev server (npm run dev doesn't run postbuild). The search only works in production builds.

# Check if the Pagefind index exists after a build:
ls public/pagefind/

# Expected output includes: pagefind-entry.json pagefind.js index/
# If the directory is empty or missing, rebuild:
npm run build

SSG not building help articles

Pagefind indexes static HTML. If the help article routes aren't being statically generated, there's no HTML for Pagefind to index. VeloCMS uses generateStaticParams to pre-render all help article routes at build time. This will fail silently if any of the following are true.

  • cookies() or headers() is called somewhere in the /help/[slug] route tree — these APIs opt the route into dynamic rendering, disabling SSG.
  • generateStaticParams in src/app/help/[slug]/page.tsx returns an empty array — this happens if HELP_ARTICLES is empty (import error) at build time.
  • export const dynamic = 'force-dynamic' was accidentally added to the help/[slug] page — remove it. Admin pages need this; help pages must NOT have it.
  • The root layout calls cookies() or headers() without being wrapped in a dynamic segment — this opts out the entire app from SSG.

Run npm run build and look at the output table. Every /help/[slug] route should show as '○ (Static)'. If any show as 'λ (Dynamic)', SSG is broken for that route and Pagefind won't index it.

The index is stale

If you added new articles but search doesn't find them, the Pagefind index is stale — it was generated before the new articles were added. This is expected behavior: the index only updates on a new build. Run npm run build to regenerate the index with the latest articles. In Railway production, every git push triggers a full rebuild, so new articles are automatically indexed on the next deploy.

Verify coverage with the built-in gate

VeloCMS has a built-in Pagefind coverage verification script that runs as part of the postbuild step. After a build, it compares the number of prerendered /help/* routes against the Pagefind index page count and fails the build if the index is significantly below the expected count. If your build passes this gate, Pagefind is working correctly.

# Run the coverage gate manually (after a build):
node scripts/verify-pagefind-coverage.mjs

# Passing output example:
# [verify-pagefind] Prerendered /help/* routes : 164
# [verify-pagefind] Pagefind total page_count  : 180
# [verify-pagefind] Required minimum           : 164

The Pagefind page count will be higher than the /help/* route count because Pagefind also indexes the public pages (/, /pricing, /blog, etc.). The coverage gate checks that the count is at least as high as the number of expected help routes — not an exact match.