| Crates.io | ruvector-router-ffi |
| lib.rs | ruvector-router-ffi |
| version | 0.1.29 |
| created_at | 2025-11-21 15:11:19.308136+00 |
| updated_at | 2025-12-29 19:17:53.741701+00 |
| description | NAPI-RS bindings for ruvector-router-core vector database |
| homepage | |
| repository | https://github.com/ruvnet/ruvector |
| max_upload_size | |
| id | 1943706 |
| size | 58,776 |
High-performance Node.js bindings for router-core vector database and neural routing engine.
NAPI-RS powered bindings bringing Rust-level performance to JavaScript/TypeScript with zero-copy buffer sharing and async/await support.
router-ffi provides seamless Node.js integration for the router-core vector database through NAPI-RS, enabling JavaScript and TypeScript applications to leverage Rust's blazing-fast performance for vector similarity search, neural routing, and embedding operations.
npm install router-ffi
const { VectorDB, DistanceMetric } = require('router-ffi');
// Create a vector database
const db = new VectorDB({
dimensions: 384,
maxElements: 10000,
distanceMetric: DistanceMetric.Cosine,
hnswM: 32,
hnswEfConstruction: 200,
hnswEfSearch: 100,
storagePath: './vectors.db'
});
// Insert a vector
const vector = new Float32Array([0.1, 0.2, 0.3, /* ... 384 dimensions */]);
const id = db.insert('doc1', vector);
console.log(`Inserted: ${id}`);
// Search for similar vectors
const query = new Float32Array([0.1, 0.2, 0.3, /* ... */]);
const results = db.search(query, 10);
results.forEach(result => {
console.log(`ID: ${result.id}, Score: ${result.score}`);
});
// Get database statistics
const count = db.count();
const allIds = db.getAllIds();
console.log(`Database contains ${count} vectors`);
const { VectorDB } = require('router-ffi');
async function main() {
const db = new VectorDB({
dimensions: 768,
distanceMetric: 'Cosine',
storagePath: './async-vectors.db'
});
// Async insert (non-blocking)
const vector = new Float32Array(768).fill(0.5);
const id = await db.insertAsync('doc1', vector);
console.log(`Inserted: ${id}`);
// Async search (non-blocking)
const query = new Float32Array(768).fill(0.5);
const results = await db.searchAsync(query, 10);
for (const result of results) {
console.log(`ID: ${result.id}, Score: ${result.score}`);
}
}
main().catch(console.error);
import { VectorDB, DistanceMetric, DbOptions, SearchResultJS } from 'router-ffi';
// Type-safe configuration
const options: DbOptions = {
dimensions: 384,
maxElements: 50000,
distanceMetric: DistanceMetric.Cosine,
hnswM: 32,
hnswEfConstruction: 200,
hnswEfSearch: 100,
storagePath: './typed-vectors.db'
};
const db = new VectorDB(options);
// Type-safe operations
const vector: Float32Array = new Float32Array(384);
const id: string = db.insert('doc1', vector);
const results: SearchResultJS[] = db.search(vector, 10);
results.forEach((result: SearchResultJS) => {
console.log(`${result.id}: ${result.score}`);
});
Main vector database class providing core operations.
new VectorDB(options: DbOptions)
DbOptions:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dimensions |
number |
Yes | - | Vector dimensionality |
maxElements |
number |
No | 1,000,000 | Maximum number of vectors |
distanceMetric |
DistanceMetric |
No | Cosine |
Distance metric |
hnswM |
number |
No | 32 | HNSW connections per node |
hnswEfConstruction |
number |
No | 200 | HNSW construction quality |
hnswEfSearch |
number |
No | 100 | HNSW search quality |
storagePath |
string |
No | ./router.db |
Database file path |
insert(id: string, vector: Float32Array): string
Insert a vector synchronously. Returns the vector ID.
Example:
const id = db.insert('doc1', new Float32Array([0.1, 0.2, 0.3]));
async insertAsync(id: string, vector: Float32Array): Promise<string>
Insert a vector asynchronously (non-blocking). Returns a Promise with the vector ID.
Example:
const id = await db.insertAsync('doc1', new Float32Array([0.1, 0.2, 0.3]));
search(queryVector: Float32Array, k: number): SearchResultJS[]
Search for similar vectors synchronously. Returns top-k results sorted by similarity.
Returns: Array of SearchResultJS objects:
id (string): Vector IDscore (number): Distance score (lower is more similar)Example:
const results = db.search(new Float32Array([0.1, 0.2, 0.3]), 10);
async searchAsync(queryVector: Float32Array, k: number): Promise<SearchResultJS[]>
Search for similar vectors asynchronously (non-blocking).
Example:
const results = await db.searchAsync(new Float32Array([0.1, 0.2, 0.3]), 10);
delete(id: string): boolean
Delete a vector by ID. Returns true if deleted, false if not found.
Example:
const deleted = db.delete('doc1');
count(): number
Get the total number of vectors in the database.
Example:
const totalVectors = db.count();
console.log(`Database contains ${totalVectors} vectors`);
getAllIds(): string[]
Get all vector IDs in the database.
Example:
const ids = db.getAllIds();
console.log(`IDs: ${ids.join(', ')}`);
Enum defining supported distance metrics:
enum DistanceMetric {
Euclidean = "Euclidean",
Cosine = "Cosine",
DotProduct = "DotProduct",
Manhattan = "Manhattan"
}
Choosing a Metric:
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install Node.js dependencies
npm install
# Build the native module (release mode)
npm run build
# Build with debug symbols
npm run build:debug
# Clean build artifacts
npm run clean
# Run tests
npm test
# Format code
cargo fmt --all
# Lint
cargo clippy --all -- -D warnings
Build for multiple platforms using NAPI-RS:
# Linux x64
npm run build -- --target x86_64-unknown-linux-gnu
# Linux ARM64
npm run build -- --target aarch64-unknown-linux-gnu
# macOS x64
npm run build -- --target x86_64-apple-darwin
# macOS ARM64 (M1/M2)
npm run build -- --target aarch64-apple-darwin
# Windows x64
npm run build -- --target x86_64-pc-windows-msvc
10,000 vectors (384D):
Operation Throughput Latency (avg)
------------------------------------------------
Insert (sync) ~2,000/sec 0.5ms
Insert (async) ~5,000/sec 0.2ms
Search (k=10) ~10,000/sec 0.1ms
Batch Insert ~8,000/sec 0.125ms
1,000,000 vectors (384D):
Operation Throughput Latency (avg)
------------------------------------------------
Insert (sync) ~1,000/sec 1.0ms
Insert (async) ~3,000/sec 0.33ms
Search (k=10) ~5,000/sec 0.2ms
Search (k=100) ~2,000/sec 0.5ms
Library Search Latency Memory (1M vectors) Language
-------------------------------------------------------------------
router-ffi 0.2ms ~600MB Rust → Node.js
Pinecone ~2ms Cloud only Hosted
Qdrant ~1ms ~1.5GB Rust
ChromaDB ~50ms ~3GB Python
FAISS ~0.5ms ~1GB C++ → Python
insertAsync and searchAsync for better throughputhnswM = better recall, more memoryefConstruction = better index quality, slower buildefSearch = better accuracy, slower searchCosine with pre-normalized vectors is fastestconst { VectorDB } = require('router-ffi');
// Create embeddings database
const db = new VectorDB({
dimensions: 1536, // OpenAI ada-002
distanceMetric: 'Cosine',
storagePath: './embeddings.db'
});
// Store document embeddings
async function indexDocument(docId, embedding) {
await db.insertAsync(docId, new Float32Array(embedding));
}
// Retrieve relevant documents
async function retrieveContext(queryEmbedding, topK = 5) {
const results = await db.searchAsync(
new Float32Array(queryEmbedding),
topK
);
return results.map(r => r.id);
}
// Index text embeddings
const documents = [
{ id: 'doc1', text: 'Machine learning basics', embedding: [...] },
{ id: 'doc2', text: 'Deep learning tutorial', embedding: [...] },
{ id: 'doc3', text: 'Neural networks explained', embedding: [...] }
];
for (const doc of documents) {
await db.insertAsync(doc.id, new Float32Array(doc.embedding));
}
// Search by semantic similarity
const query = 'AI fundamentals';
const queryEmbedding = await getEmbedding(query);
const results = await db.searchAsync(new Float32Array(queryEmbedding), 3);
// Store user/item embeddings
const userEmbeddings = new Map();
const itemEmbeddings = new Map();
// Index items
for (const [itemId, embedding] of itemEmbeddings) {
await db.insertAsync(`item_${itemId}`, new Float32Array(embedding));
}
// Find similar items
function recommendSimilar(itemId, count = 10) {
const embedding = itemEmbeddings.get(itemId);
const results = db.search(new Float32Array(embedding), count + 1);
return results.slice(1); // Exclude self
}
// Store agent experiences
class AgentMemory {
constructor(dimensions) {
this.db = new VectorDB({
dimensions,
distanceMetric: 'Cosine',
storagePath: './agent-memory.db'
});
}
async remember(experience, embedding) {
const id = `exp_${Date.now()}`;
await this.db.insertAsync(id, new Float32Array(embedding));
return id;
}
async recall(queryEmbedding, count = 5) {
return await this.db.searchAsync(
new Float32Array(queryEmbedding),
count
);
}
}
router-ffi uses Rust's Arc<T> for thread-safe reference counting, making it safe to use across Node.js worker threads:
const { Worker } = require('worker_threads');
const { VectorDB } = require('router-ffi');
// Main thread
const db = new VectorDB({ dimensions: 384 });
// Workers can safely share the database
const worker = new Worker('./worker.js');
// Good: Reuse instance
const db = new VectorDB({ dimensions: 384 });
for (let i = 0; i < 1000; i++) {
await db.insertAsync(`doc${i}`, vector);
}
// Bad: Creating new instances
for (let i = 0; i < 1000; i++) {
const db = new VectorDB({ dimensions: 384 }); // Expensive!
await db.insertAsync(`doc${i}`, vector);
}
| Platform | Architecture | Status | Notes |
|---|---|---|---|
| Linux | x86_64 | ✅ Supported | glibc 2.17+ |
| Linux | aarch64 | ✅ Supported | ARM64 servers |
| macOS | x86_64 | ✅ Supported | Intel Macs |
| macOS | aarch64 | ✅ Supported | M1/M2/M3 Macs |
| Windows | x86_64 | ✅ Supported | MSVC runtime |
| Windows | aarch64 | ⚠️ Experimental | ARM64 Windows |
NAPI-RS provides pre-built binaries for common platforms. If your platform isn't supported, the module will compile from source automatically.
Error: cargo not found
Install Rust toolchain:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
Error: NAPI-RS build failed
Update NAPI-RS CLI:
npm install -g @napi-rs/cli@latest
Error: Cannot find native module
Rebuild the native module:
npm rebuild router-ffi
Error: Vector dimension mismatch
Ensure all vectors have the same dimensions as specified in DbOptions:
const db = new VectorDB({ dimensions: 384 });
// ✅ Correct
db.insert('doc1', new Float32Array(384));
// ❌ Wrong - dimension mismatch
db.insert('doc2', new Float32Array(768)); // Error!
Slow search performance
hnswEfSearch for better recallsearchAsync instead of searchHigh memory usage
maxElements if you don't need ithnswM value (trades accuracy for memory)The HNSW (Hierarchical Navigable Small World) index provides fast approximate nearest neighbor search:
const db = new VectorDB({
dimensions: 384,
hnswM: 32, // Connections per node (16-64)
hnswEfConstruction: 200, // Build quality (100-500)
hnswEfSearch: 100 // Search quality (10-200)
});
Parameter Guidelines:
| Parameter | Low Value | High Value | Trade-off |
|---|---|---|---|
hnswM |
16 | 64 | Memory vs Recall |
efConstruction |
100 | 500 | Speed vs Quality |
efSearch |
10 | 200 | Speed vs Accuracy |
// Cosine Similarity (angle between vectors)
// Range: [0, 2], lower is more similar
// Best for: Normalized embeddings, semantic search
const db1 = new VectorDB({ distanceMetric: 'Cosine' });
// Euclidean Distance (L2 norm)
// Range: [0, ∞), lower is more similar
// Best for: Spatial data, general purpose
const db2 = new VectorDB({ distanceMetric: 'Euclidean' });
// Dot Product (inner product)
// Range: (-∞, ∞), higher is more similar
// Best for: Pre-normalized vectors
const db3 = new VectorDB({ distanceMetric: 'DotProduct' });
// Manhattan Distance (L1 norm)
// Range: [0, ∞), lower is more similar
// Best for: Robust to outliers
const db4 = new VectorDB({ distanceMetric: 'Manhattan' });
// Efficient batch insert
async function batchInsert(vectors) {
const promises = vectors.map((vec, idx) =>
db.insertAsync(`doc${idx}`, new Float32Array(vec))
);
return await Promise.all(promises);
}
// Parallel search
async function batchSearch(queries, k = 10) {
const promises = queries.map(query =>
db.searchAsync(new Float32Array(query), k)
);
return await Promise.all(promises);
}
Complete examples are available in the examples directory:
Run examples:
npm run build
node examples/basic.js
node examples/async.js
ts-node examples/typescript.ts
router-ffi wraps the router-core Rust crate, providing:
See router-core for core implementation details.
Contributions are welcome! See CONTRIBUTING.md for guidelines.
# Clone repository
git clone https://github.com/ruvnet/ruvector.git
cd ruvector/crates/router-ffi
# Install dependencies
npm install
# Build in development mode
npm run build:debug
# Run tests
npm test
# Format code
cargo fmt --all
# Lint
cargo clippy --all -- -D warnings
# Run all tests
npm test
# Run specific test
npm test -- --grep "search"
# Run benchmarks
npm run bench
MIT License - see LICENSE for details.
Built with cutting-edge technologies: