A fast HNSW (Hierarchical Navigable Small World) vector database implementation in C++ with WebAssembly bindings for JavaScript, React, and Angular.
This project includes three ready-to-use packages for web applications:
Core WebAssembly module with JavaScript/TypeScript bindings.
npm install @simple-vectordb/wasmReact hooks and components for easy integration.
npm install @simple-vectordb/react @simple-vectordb/wasmAngular service and module for seamless integration.
npm install @simple-vectordb/angular @simple-vectordb/wasmimport { initializeWasm, SimpleVectorDB } from '@simple-vectordb/wasm';
// Initialize WASM (do this once)
await initializeWasm();
// Create database
const db = new SimpleVectorDB(5, 0.62, 10);
// Insert vectors
db.insert([1.0, 2.0, 3.0]);
// Search for nearest neighbors
const results = db.search([1.1, 2.1, 3.1], 5);
// Save to JSON
const json = db.toJSON();
// Load from JSON
const db2 = await SimpleVectorDB.fromJSON(json);
// Cleanup
db.delete();import { VectorDBProvider, useVectorDB } from '@simple-vectordb/react';
function App() {
return (
<VectorDBProvider>
<VectorSearch />
</VectorDBProvider>
);
}
function VectorSearch() {
const { insert, search, save, load, isReady } = useVectorDB();
const handleInsert = () => {
insert([1.0, 2.0, 3.0]);
};
const handleSearch = () => {
const results = search([1.1, 2.1, 3.1], 5);
console.log(results);
};
const handleSave = () => {
const json = save();
localStorage.setItem('db', json);
};
const handleLoad = async () => {
const json = localStorage.getItem('db');
await load(json);
};
if (!isReady) return <div>Loading...</div>;
return (
<div>
<button onClick={handleInsert}>Insert</button>
<button onClick={handleSearch}>Search</button>
<button onClick={handleSave}>Save</button>
<button onClick={handleLoad}>Load</button>
</div>
);
}import { Component, OnInit, OnDestroy } from '@angular/core';
import { VectorDBService } from '@simple-vectordb/angular';
@Component({
selector: 'app-search',
template: `
<button (click)="insert()">Insert</button>
<button (click)="search()">Search</button>
<button (click)="saveDB()">Save</button>
<button (click)="loadDB()">Load</button>
<div *ngFor="let result of results">
Distance: {{ result.distance }}, Index: {{ result.nodeIndex }}
</div>
`
})
export class SearchComponent implements OnInit, OnDestroy {
results = [];
constructor(private vectorDB: VectorDBService) {}
async ngOnInit() {
await this.vectorDB.createDatabase(5, 0.62, 10);
}
insert() {
this.vectorDB.insert([1.0, 2.0, 3.0]).subscribe(
() => console.log('Inserted')
);
}
search() {
this.vectorDB.search([1.1, 2.1, 3.1], 5).subscribe(
results => this.results = results
);
}
saveDB() {
this.vectorDB.save().subscribe(
json => localStorage.setItem('db', json)
);
}
loadDB() {
const json = localStorage.getItem('db');
this.vectorDB.load(json).subscribe(
() => console.log('Loaded')
);
}
ngOnDestroy() {
this.vectorDB.destroy();
}
}- Fast HNSW Algorithm: Efficient approximate nearest neighbor search
- WebAssembly: Near-native C++ performance in the browser
- TypeScript Support: Full type definitions included
- Framework Integration: Purpose-built hooks and services for React and Angular
- Persistence: Save and load indexes as JSON
- Memory Management: Proper cleanup and resource management
- RxJS Integration: Observable-based API for Angular
- React Hooks: Modern React patterns with hooks and context
- Semantic Search: Find similar text embeddings
- Image Search: Search similar image vectors
- Recommendation Systems: Find similar items
- Clustering: Group similar vectors
- Anomaly Detection: Find outliers in vector space
All packages support HNSW configuration parameters:
new SimpleVectorDB(L, mL, efc)Parameters:
-
L (default: 5): Number of layers in HNSW graph
- Higher = Better recall, more memory
- Typical range: 3-10
-
mL (default: 0.62): Layer assignment multiplier
- Controls layer distribution
- Usually keep at 0.62
-
efc (default: 10): Construction search breadth
- Higher = Better quality, slower build
- Typical range: 5-50
- C++ compiler with C++17 support
- CMake 3.10+
- Emscripten SDK (for WebAssembly)
- Node.js 14+ (for packages)
# Create build directory
mkdir build
cd build
# Configure with CMake
cmake ..
# Compile
make
# Run
./SimpleHNSW# Set up Emscripten environment
source /path/to/emsdk/emsdk_env.sh
# Run build script (builds and copies to packages)
./build-packages.sh# Set up Emscripten environment
source /path/to/emsdk/emsdk_env.sh
# Create build directory
mkdir build-wasm
cd build-wasm
# Configure with CMake
emcmake cmake -DEMSCRIPTEN=1 ..
# Build
emmake make
# Copy outputs to package directory
cp simple-vectordb.js simple-vectordb.wasm ../packages/simple-vectordb-wasm/# Build WASM first
./build-packages.sh
# Publish core WASM package
cd packages/simple-vectordb-wasm
npm publish --access public
# Publish React package
cd ../react-simple-vectordb
npm publish --access public
# Publish Angular package
cd ../angular-simple-vectordb
npm publish --access publicsimple-vectordb-cpp/
βββ src/ # C++ source code
β βββ simple_hnsw.h # Core HNSW implementation
β βββ wasm_bindings.cpp # Emscripten bindings
β βββ priority_queue.h # Data structures
β βββ lru_cache.h # Caching utilities
β βββ util.cpp # Helper functions
βββ packages/
β βββ simple-vectordb-wasm/ # Core WASM package
β β βββ index.js # JavaScript wrapper
β β βββ simple-vectordb.d.ts # TypeScript definitions
β β βββ simple-vectordb.js/.wasm # Built files
β βββ react-simple-vectordb/ # React package
β β βββ src/
β β βββ hooks.js # React hooks
β β βββ context.js # React context
β βββ angular-simple-vectordb/ # Angular package
β βββ src/lib/
β βββ vector-db.service.ts
β βββ vector-db.module.ts
βββ examples/
β βββ react-example/ # React demo app
β βββ angular-example/ # Angular demo app
βββ CMakeLists.txt # CMake configuration
βββ build-packages.sh # Build automation script
βββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β (React/Angular Applications) β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββββββββ
β Framework Layer β
β (@simple-vectordb/react|angular) β
β β’ Hooks/Services β
β β’ Lifecycle Management β
β β’ State Management β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββββββββ
β Core WASM Layer β
β (@simple-vectordb/wasm) β
β β’ JavaScript API β
β β’ Type Conversions β
β β’ Memory Management β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββββββββ
β WebAssembly Module β
β (simple-vectordb.wasm) β
β β’ HNSW Algorithm β
β β’ Vector Operations β
β β’ Distance Calculations β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββββββββ
β C++ Implementation β
β β’ SimpleHNSWIndex β
β β’ Core algorithms β
β β’ Data structures β
βββββββββββββββββββββββββββββββββββββββββββ
Complete example applications are available:
interface SearchResult {
distance: number;
nodeIndex: number;
}
// React
interface UseVectorDBResult {
db: SimpleVectorDB | null;
insert: (vector: number[]) => void;
search: (query: number[], k: number) => SearchResult[];
save: () => string;
load: (json: string) => Promise<void>;
isReady: boolean;
}
// Angular - all methods return Observables
class VectorDBService {
initialize(): Observable<void>;
createDatabase(L?: number, mL?: number, efc?: number): Promise<void>;
insert(vector: number[]): Observable<void>;
search(query: number[], k: number): Observable<SearchResult[]>;
save(): Observable<string>;
load(json: string): Observable<void>;
destroy(): void;
}try {
insert(vector);
const results = search(query, k);
} catch (error) {
console.error('Operation failed:', error);
}this.vectorDB.search(query, k).subscribe({
next: results => this.results = results,
error: error => console.error('Search failed:', error)
});- Batch inserts: Insert all vectors before searching
- Appropriate k: Don't request more results than needed
- Memory management: Call
delete()on WASM instances when done - Persistence: Use binary formats for large databases (future enhancement)
- Dimensions: Keep vector dimensions consistent across all operations
- Chrome 57+
- Firefox 52+
- Safari 11+
- Edge 16+
Contributions are welcome! Please feel free to submit a Pull Request.
MIT
