HnswLite.RamStorage 1.1.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package HnswLite.RamStorage --version 1.1.1
                    
NuGet\Install-Package HnswLite.RamStorage -Version 1.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HnswLite.RamStorage" Version="1.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HnswLite.RamStorage" Version="1.1.1" />
                    
Directory.Packages.props
<PackageReference Include="HnswLite.RamStorage" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add HnswLite.RamStorage --version 1.1.1
                    
#r "nuget: HnswLite.RamStorage, 1.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package HnswLite.RamStorage@1.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=HnswLite.RamStorage&version=1.1.1
                    
Install as a Cake Addin
#tool nuget:?package=HnswLite.RamStorage&version=1.1.1
                    
Install as a Cake Tool

<img src="https://github.com/jchristn/HnswLite/blob/main/assets/logo.png" width="256" height="256">

HnswLite

A pure C# implementation of Hierarchical Navigable Small World (HNSW) graphs for approximate nearest neighbor search. HnswLite ships as an embeddable library, a REST server, a React dashboard, and SDKs in three languages.

Note: This library is in its early stages of development. We welcome your patience, constructive feedback, and contributions! Please be kind and considerate when reporting issues or suggesting improvements. I am not an expert on this topic and relied heavily on available AI tools to build this library. Pull requests are greatly appreciated!

NuGet Version NuGet

Overview

HnswLite implements the Hierarchical Navigable Small World algorithm, which provides fast approximate nearest-neighbor search with excellent recall rates. The library is designed to be embeddable, extensible, and easy to use from any .NET application — or from Python / JavaScript / any HTTP client via the REST server.

Repository layout

Path Purpose
src/HnswIndex/ Core library (HnswLite on NuGet)
src/HnswIndex.RamStorage/ In-memory storage provider
src/HnswIndex.SqliteStorage/ SQLite storage provider
src/HnswIndex.Server/ Standalone REST server (Watson 7)
src/Test.Shared/ + src/Test.{Automated,XUnit,NUnit,MSTest}/ Touchstone-driven test suites
dashboard/ React 19 + Vite dashboard
sdk/csharp/, sdk/python/, sdk/js/ Client SDKs with 100% endpoint coverage
docker/ compose.yaml for server + dashboard, plus factory-reset scripts

Key features

  • Pure C# implementation — no native dependencies.
  • Thread-safe, async/await with cancellation tokens throughout.
  • Unified IStorageProvider interface — build-your-own backend by implementing one interface.
  • Multiple distance metrics — Euclidean, Cosine, Dot Product, with SIMD acceleration via System.Numerics.Vector<float>.
  • Batch operations — efficient bulk insert and remove.
  • Persistence by default — the SQLite storage provider writes a self-describing .db file; the REST server reloads every index on startup.
  • Paginated enumeration contract across every GET collection endpoint (EnumerationQuery / EnumerationResult<T>).
  • OPTIONS preflight + CORS out of the box in the REST server.

New in v1.1.0

See CHANGELOG.md for the full list. Highlights:

  • Multi-target net8.0 + net10.0.
  • Unified IStorageProvider with RamStorageProvider and SqliteStorageProvider.
  • Watson web server upgraded to 7.0.11 with CORS + OPTIONS preflight.
  • Every GET-collection endpoint now paginated via EnumerationQuery / EnumerationResult<T>.
  • Default server StorageType is SQLite — indexes persist across restarts, metadata lives inside the .db file (no separate manifest).
  • New GET /v1.0/indexes/{name}/vectors (paginated) and GET /v1.0/indexes/{name}/vectors/{guid} endpoints.
  • SIMD distance functions + a dozen internal performance fixes — see PERFORMANCE_IMPROVEMENTS.md.
  • New dashboard, new SDKs (C#, Python, JS), new Touchstone test suite (53 cases × 4 runners).

Use cases

  • Semantic search — find similar documents / sentences from embeddings.
  • Recommendation systems — discover similar items / users / content.
  • Image similarity — search on feature vectors.
  • Anomaly detection — identify outliers by neighbour distance.
  • Clustering — group similar items.
  • RAG — retrieval-augmented generation for LLM applications.
  • Duplicate detection — find near-duplicate content at scale.

Performance & scalability

  • Vector dimensions: 50–1000 (optimal: 128–768).
  • Dataset size: up to 1–10M vectors depending on dimension and RAM.
  • Memory usage: approximately (vector_count × dimension × 4 bytes) + (vector_count × M × 32 bytes).

These are estimates. The library has not been exhaustively load-tested.

Parameters

  • M — connections per vector (default 16). More connections → better recall, more memory. 16–32 works well for most cases.
  • EfConstruction — construction search depth (default 200). Higher → better graph quality, slower builds. Drop to 50–100 for fast batch insertion.
  • Ef — search depth (default 50–200). Higher → better recall, slower search.
  • Seed — fix for reproducible builds.

Tips

  • Use AddNodesAsync(...) / RemoveNodesAsync(...) for batches — they acquire the write lock once.
  • Prefer SqliteStorageProvider for persistence; RamStorageProvider for ephemeral in-memory indexes.
  • For high-dimensional embeddings use CosineDistance.

Simple example (embedded)

using Hnsw;
using Hnsw.RamStorage;
using HnswIndex.SqliteStorage;

// RAM
using RamStorageProvider ram = new RamStorageProvider();
HnswIndex index = new HnswIndex(128, ram);

// Or SQLite (persistent)
using SqliteStorageProvider sqlite = new SqliteStorageProvider("my-index.db");
HnswIndex persistentIndex = new HnswIndex(128, sqlite);

// Configure
index.M = 16;
index.EfConstruction = 200;
index.DistanceFunction = new CosineDistance();

// Add a single vector
Guid id = Guid.NewGuid();
List<float> vector = new List<float>(128); // your 128-d embedding
await index.AddAsync(id, vector);

// Add a batch
Dictionary<Guid, List<float>> batch = new Dictionary<Guid, List<float>>();
for (int i = 0; i < 1000; i++) batch[Guid.NewGuid()] = GenerateRandomVector(128);
await index.AddNodesAsync(batch);

// Search
List<float> query = new List<float>(128);
IEnumerable<VectorResult> neighbors = await index.GetTopKAsync(query, count: 10);
foreach (VectorResult r in neighbors)
    Console.WriteLine($"id={r.GUID} distance={r.Distance:F4}");

// Export / import state
HnswState state = await index.ExportStateAsync();
HnswIndex restored = new HnswIndex(128, new RamStorageProvider());
await restored.ImportStateAsync(state);

Best practices

  1. Resource management. IStorageProvider is IDisposable — use using to guarantee flush on scope exit (important for SQLite).
  2. Prefer batches. Calling AddNodesAsync is substantially faster than a loop of AddAsync because it acquires the write lock once.
  3. Tune Ef at search time.
    IEnumerable<VectorResult> quick  = await index.GetTopKAsync(query, 10, ef: 50);   // fast, lower recall
    IEnumerable<VectorResult> better = await index.GetTopKAsync(query, 10, ef: 400);  // slower, higher recall
    

Custom storage backend

Implement IStorageProvider (which aggregates IHnswStorage, IHnswLayerStorage, and IDisposable). See RamStorageProvider and SqliteStorageProvider as reference implementations. The server and dashboard are completely provider-agnostic.

REST server

cd src/HnswIndex.Server
dotnet run -- --setup      # writes hnswindex.json with a generated admin API key
dotnet run

The server listens on http://localhost:8080 by default. Authentication uses the x-api-key header (configurable via Server.AdminApiKeyHeader). OPTIONS pre-flight is unauthenticated and served by Watson's preflight hook; CORS headers are emitted on every response and configured under the Cors block in hnswindex.json.

Full endpoint reference: REST_API.md. Interactive reference: HNSW Index.postman_collection.json.

Dashboard

React 19 + Vite 6 + TypeScript dashboard at dashboard/. Pages include Indices, Vectors (browse / edit / add / delete), Search, Request History with an activity chart, API Explorer, Server Info, Settings, plus a login flow.

# Local development
cd dashboard
npm install
HNSWLITE_SERVER_URL=http://localhost:8080 npm run dev

# Production build (static assets in dashboard/dist)
npm run build

SDKs

Language Directory Package Runtime
C# sdk/csharp/ HnswLite.Sdk .NET 8 or .NET 10
Python sdk/python/ hnswlite-sdk Python 3.9+
JavaScript / TypeScript sdk/js/ hnswlite-sdk Node 18+ (native fetch)

Each SDK has 100% endpoint coverage and a test harness. See sdk/README.md for the method matrix and per-language READMEs.

Docker

cd docker
docker compose up -d
  • Server: http://localhost:8080/
  • Dashboard: http://localhost:8081/dashboard/

Factory reset (with RESET confirmation):

cd docker/factory
./reset.sh      # or reset.bat on Windows

See docker/README.md for image tags and environment overrides.

Bugs, feedback, or enhancement requests

  • Bug reports: please file an issue with reproduction steps.
  • Feature requests: open a discussion or create an issue.
  • Questions: use the discussions forum.
  • Contributions: pull requests welcome.

License

MIT. See LICENSE.md.

Acknowledgments

Based on Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs by Yu. A. Malkov and D. A. Yashunin.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 115 4/17/2026
1.1.2 110 4/17/2026
1.1.1 108 4/16/2026
1.1.0 109 4/16/2026
1.0.6 2,670 9/2/2025
1.0.5 258 8/29/2025
1.0.4 236 8/25/2025
1.0.3 191 8/24/2025
1.0.2 502 7/21/2025
1.0.1 402 7/21/2025
1.0.0 400 7/21/2025

Initial release