A native .NET port of the Pagefind indexer — build search indexes in-process, no subprocess, no shelling out. Compatible with the official Pagefind JS/WASM query runtime.
using Pagefind.Net; var index = new PagefindIndex(new PagefindIndexOptions { Language = "en" }); index.AddRecord(new PagefindRecord { Url = "/guide/", Title = "Getting started", Content = plainTextBody, WeightedSegments = [ new WeightedSegment(h1Text, Weight: 7), new WeightedSegment(bodyText, Weight: 1), ], }); await index.WriteAsync("wwwroot"); // writes pagefind/ — ready for pagefind.js
// what you get
pagefind-net reimplements the Pagefind indexer in managed C#, producing the same
pagefind/ directory the official JS/WASM query runtime consumes — byte for byte.
Index generation runs inside your .NET process. No binary to locate, no
Process.Start, no exit codes to parse. Just a method call.
Produces identical .pf_meta, .pf_index, and .pf_fragment
files to the official Pagefind binary. The standard pagefind.js query runtime
works without modification.
Zero-allocation tokeniser and stemmer on hot paths.
Concurrent AddRecord with O(1) memory pressure and per-record error attribution.
No reflection, no dynamic dispatch. Trims cleanly and publishes as a native binary. AOT-compatible end-to-end — tested on Linux, macOS, and Windows.
Pagefind.Net.Frontend ships the Pagefind JS/WASM runtime. An MSBuild target
auto-extracts the files into your project on build — no manual steps.
Pass WeightedSegments to boost headings and create sub-page anchors —
same as the official binary's structured indexing API.
// why pagefind-net
The official Pagefind CLI is a great tool — but calling it from .NET means shelling out: locating a binary, managing a subprocess, parsing exit codes. pagefind-net removes that entirely by running the same logic in-process as a native .NET library.
Index generation is a method call, not a shell command. No binary to ship alongside your app, no path resolution at runtime, no stdout/stderr to parse. Errors surface as typed .NET exceptions, not process exit codes.
The official CLI ships separate platform-specific binaries. pagefind-net runs anywhere .NET runs — any OS, any CPU, any container, any CI runner. One NuGet package, no conditionals, no runtime downloads.
AddRecord is safe to call concurrently from multiple threads. Integrate
index generation directly into your ASP.NET Core pipeline, Blazor app, or build
system — no inter-process coordination required.
The test suite runs both pagefind-net and the official CLI on the same input and diffs
the output. Encoding, tokenization, and file layout are verified byte-for-byte. The
query side — pagefind.js, your UI, your search component — stays unchanged.
// quick start
Add the indexer, point it at your documents, call WriteAsync.
Add the frontend package and your MSBuild target handles the rest.
dotnet add package Pagefind.Net — targets net9.0 and later.
No native or JavaScript transitive dependencies.
Create a PagefindIndex, call AddRecord for each page —
concurrently if you like. Pass WeightedSegments to boost headings
and generate per-heading anchors.
Call await index.WriteAsync("wwwroot"). The pagefind/
directory is written and ready for the standard Pagefind JS runtime to query.
Add Pagefind.Net.Frontend — an MSBuild target extracts
pagefind.js and wasm.en.pagefind into your project automatically.
var index = new PagefindIndex( new PagefindIndexOptions { Language = "en" }); // AddRecord is thread-safe await Parallel.ForEachAsync(pages, async (page, _) => { index.AddRecord(new PagefindRecord { Url = page.Url, Title = page.Title, Content = page.PlainText, WeightedSegments = [ new WeightedSegment(page.H1, Weight: 7), new WeightedSegment(page.Body, Weight: 1), ] }); }); await index.WriteAsync("wwwroot");
using Pagefind.Net.Frontend; // extract pagefind.js + wasm to wwwroot/pagefind await PagefindFrontend.ExtractToAsync("wwwroot");
One NuGet package. Pagefind search indexing that runs inside your .NET process — no shelling out, no binary to ship.