---
title: "oneindex"
url: https://recursiveai.org/oneindex/
description: "An embedded search engine for .NET, written in C# with no native code and no server: full-text (BM25F), vector (HNSW) and hybrid search, reranking with bundled models, EF Core and folder indexing with citations. A preview. MIT or Apache-2.0."
---

# oneindex

An embedded search engine for .NET: full-text, vector and hybrid search in one in-process library, written in C# with no native code and no server.

```sh
dotnet add package RecursiveAI.OneIndex --prerelease
```

- [Getting started](https://recursiveai.org/oneindex/docs/getting-started/)
- [Docs](https://recursiveai.org/oneindex/docs/)
- [Cookbook](https://recursiveai.org/oneindex/cookbook/)
- [GitHub](https://github.com/recursive-ai-oss/oneindex-csharp)
- [NuGet](https://www.nuget.org/packages/RecursiveAI.OneIndex)

## A quick look

Mark an ordinary class, upsert, commit, and search with what the user typed. A source generator writes the mapping at build time, so there is no reflection and it runs under NativeAOT.

[Getting started](https://recursiveai.org/oneindex/docs/getting-started/)

*Program.cs · C#*

```
using var index = SearchIndex.Open<Invoice>("data/search");
index.Upsert(invoices);
index.Commit();   // atomic and durable
 
// words, "phrases", -exclusions; typos forgiven
var hits = index.Search("overdue \"acme corp\" -draft")
    .Where(x => x.Tags.Contains("invoice"))
    .Take(10);
```

### Full-text search

BM25F ranking, phrases, prefix, fuzzy and regex queries, typo tolerance and as-you-type, synonyms, “did you mean”, Snowball stemmers for 34 languages, and Asian segmentation in an add-on package.

[Full-text search in C#](https://recursiveai.org/oneindex/cookbook/full-text-search-csharp/)

### Vector search

HNSW and exact search, int8, int4 and sign-bit compressed copies with exact rerank, filters that steer the graph walk, learned sparse vectors and multi-vector MaxSim.

[Vector search in .NET](https://recursiveai.org/oneindex/cookbook/vector-search-dotnet/)

### Hybrid and rerank

Keyword and vector lists fused in one ranking, then a cross-encoder over the best hits. The embedder and reranker are bundled and run in your process; text is embedded at upsert and cached.

[Hybrid search with reranking](https://recursiveai.org/oneindex/cookbook/hybrid-search-reranking-csharp/)

### Filters, facets and sorting

LINQ `Where` translated to index filters, filter strings, facets with value search, aggregations, distinct, geo, sorting with search-after, function scores and ranking rules.

[Facets and distinct](https://recursiveai.org/oneindex/docs/facets/)

### EF Core

`SaveChanges` logs each change in the same transaction, and the index is updated from the database. One `Where` runs partly in the index and partly in the database. Verified on SQLite and PostgreSQL 16; SQL Server and MySQL have not been run. `ExecuteUpdate`, `ExecuteDelete` and raw SQL need `ReindexAsync`.

[Search EF Core entities](https://recursiveai.org/oneindex/cookbook/search-ef-core-entities/)

### Folders, with citations

PDF, Markdown, HTML, text and archives cut into passages; every hit cites its file, page and exact character range. OCR for scans in an add-on. A command-line tool does the same.

[Search a folder with citations](https://recursiveai.org/oneindex/cookbook/search-folder-files-citations-csharp/)

### In the browser

Memory and OPFS storage, and a static index any file server can host, read over plain HTTP. Heavier than Pagefind, in the README’s words: “a first query costs about 0.65 MB, or 0.74 MB with the manifest (Pagefind: 0.32 MB) and a later text query about 194 KB in 48 small requests (Pagefind: 46 KB in 4)”.

[Static index](https://recursiveai.org/oneindex/docs/static-index/)

### Query surfaces

User text that never throws, an opt-in strict syntax with positioned errors, versioned query JSON, and `SearchTool.For<T>()`, which offers a search to an LLM as a tool with a schema.

[User text](https://recursiveai.org/oneindex/docs/user-text/)

### From Lucene.NET

A call-by-call mapping from Lucene.NET 4.8, analysis equivalences and a worked example. OneIndex can’t open a Lucene index: reindex from your source of truth.

[Migrate from Lucene.NET](https://recursiveai.org/oneindex/cookbook/migrate-from-lucene-net/)

## Relevance and speed

The project’s own measurements at the release, with their conditions in the [relevance](https://recursiveai.org/oneindex/docs/relevance/) and [benchmark](https://recursiveai.org/oneindex/docs/benchmarks/) pages.

- **Relevance, BM25.** nDCG@10 on BEIR test sets, OneIndex at its defaults against Lucene.NET 4.8.0-beta00018’s flat layout on the same runs: SciFact 0.6918 against 0.6789, ArguAna 0.4347 against 0.4118, NQ 0.3452 against 0.3058, SCIDOCS 0.1544 against 0.1509. Summing per-field scores in Lucene.NET does better on SCIDOCS (0.1587).
- **Relevance, hybrid.** BM25 with the bundled bge-small-en-v1.5 at the default fusion averages 0.5168 over SciFact, ArguAna, SCIDOCS and NQ, against 0.5058 for the vector arm alone and 0.4049 for BM25, and is above both arms on every set. The defaults were tuned on the first three; NQ was held out.
- **Text speed against Lucene.NET.** 302,567 Wikipedia abstracts, matched analysis and commits, 17 rows from indexing and commit to phrase, fuzzy, facet, sort and function-score queries. Each ratio is OneIndex’s time over Lucene.NET’s, so **below 1 is faster**: geometric mean 0.62 on x64 (AMD Ryzen 9 7950X3D, Linux) and 0.41 on arm64 (Apple M2, macOS; 0.57 without the Stats and Sort rows, where Lucene.NET’s arm64 times are outliers). The slowest rows: Phrase 1.17 and FunctionScore 1.14, both on x64. The index is larger, 60.6 MB against 45.4 MB, because each document’s source is stored.
- **Vector speed against Hnsw.Net 0.1.4.** At matched recall@10 (0.90, 0.95 and 0.99, or the highest both reach), 384 and 768 dimensions. Each ratio is OneIndex’s queries per second over Hnsw.Net’s, so **above 1 is faster**: geometric mean 1.19 on x64 and 1.15 on arm64; the lowest row is 1.04 (768 dimensions at 0.99, arm64).
- **Native engines** are listed for information. In the project’s words, “Tantivy is 2-3x faster on plain term and phrase queries.”

## What a commit promises

A commit that returns survives a crash or `kill -9` of your process, a reader sees one whole commit, and every file is checksummed, so damage fails the open with an error naming the file instead of returning wrong results.

- **How it is tested.** The project’s own testing: fault injection at every storage operation (about 890,000 schedules on x64 and arm64) and more than 7,000 process kills during writes, merges, schema changes and multi-process reading, with no failed open and no lost commit.
- **Power cuts.** From the README: “On a power cut the index may roll back to an earlier commit, but it is never corrupt.” Power cuts were not exercised on real hardware.
- **Windows.** The full test suite runs on Windows on every change; the kill and fault-injection campaigns run on Linux and macOS only.
- **Conditions.** A local file system that honors `fsync` and atomic rename; network and FUSE file systems are not supported. One writer per index directory.

[Promises, conditions and every test](https://recursiveai.org/oneindex/docs/durability/)

## Status and packages

- **Status**: A preview, 0.4.0-preview.2. From the README: “on nuget.org as prerelease packages (`0.4.0-preview.1` and later; add `--prerelease` or a version when installing).” “Everything in the table below works and is tested; APIs and file formats may still change between previews.” Known gaps are listed in the [overview](https://recursiveai.org/oneindex/docs/overview/).
- **OneIndex**: `RecursiveAI.OneIndex`: the engine and the happy path, with no dependencies beyond .NET. Preview, 0.4.0-preview.2.
- **Models**: `RecursiveAI.OneIndex.Models`: bge-small-en-v1.5 embedder (MIT), ms-marco-MiniLM-L6-v2 cross-encoder reranker (Apache-2.0) and an OpenSearch learned sparse encoder (Apache-2.0), int8 weights inside a 134 MB package. `.Models.Multilingual`: multilingual-e5-small (MIT), 112 MB. The weights keep their own licenses; the terms of the data they were trained on are the data owners’ and are not conferred on them.
- **Integrations**: `.EntityFrameworkCore` (EF Core 10), `.VectorData` (Microsoft.Extensions.VectorData; dynamic collections, store-side embedding, Manhattan and Hamming distance aren’t supported), `.Files` and `.Files.Ocr` (on onepdf, onehtml, onearchive and oneocr), `.Analysis.Asian`, and `.Cli`, the `oneindex` tool. Preview, 0.4.0-preview.2.
- **.NET**: .NET 10, C#, no native code; trimming and NativeAOT for the core. MIT or Apache-2.0.

## Go further

- [GitHub](https://github.com/recursive-ai-oss/oneindex-csharp)
- [NuGet](https://www.nuget.org/packages/RecursiveAI.OneIndex)
- [Getting started](https://recursiveai.org/oneindex/docs/getting-started/)
- [All docs](https://recursiveai.org/oneindex/docs/)
- [Cookbook](https://recursiveai.org/oneindex/cookbook/)
- [Benchmarks](https://recursiveai.org/oneindex/docs/benchmarks/)
- [Changelog](https://recursiveai.org/oneindex/docs/changelog/)

OneIndex is unaffiliated with other products named OneIndex, OneSearch or similar.
