npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wiscale/velesdb-wasm

v1.15.0

Published

VelesDB for WebAssembly - Vector search in the browser

Downloads

802

Readme

VelesDB WASM

npm License

WebAssembly build of VelesDB - vector search in the browser.

Features

  • In-browser vector search - No server required
  • Multiple metrics - Cosine, Euclidean, Dot Product, Hamming, Jaccard
  • Memory optimization - SQ8 (4x) and Binary (32x) quantization
  • Knowledge Graph - In-memory graph store with BFS/DFS traversal
  • Agent Memory - Semantic memory for AI agents (store/query knowledge facts)
  • VelesQL parser - Parse and validate VelesQL queries client-side
  • Sparse search - Inverted index with RRF hybrid fusion
  • Lightweight - Minimal bundle size

Installation

npm install @wiscale/velesdb-wasm

Usage

import init, { VectorStore } from '@wiscale/velesdb-wasm';

async function main() {
  // Initialize WASM module
  await init();

  // Create a vector store (768 dimensions, cosine similarity)
  const store = new VectorStore(768, 'cosine');

  // Insert vectors (use BigInt for IDs)
  store.insert(1n, new Float32Array([0.1, 0.2, ...]));
  store.insert(2n, new Float32Array([0.3, 0.4, ...]));

  // Search for similar vectors
  const query = new Float32Array([0.15, 0.25, ...]);
  const results = store.search(query, 5); // Top 5 results

  // Results: [[id, score], [id, score], ...]
  console.log(results);
}

main();

High-Performance Bulk Insert

For optimal performance when inserting many vectors:

// Pre-allocate capacity (avoids repeated memory allocations)
const store = VectorStore.with_capacity(768, 'cosine', 100000);

// Batch insert (much faster than individual inserts)
const batch = [
  [1n, [0.1, 0.2, ...]],
  [2n, [0.3, 0.4, ...]],
  // ... more vectors
];
store.insert_batch(batch);

// Or reserve capacity on existing store
store.reserve(50000);

API

VectorStore

class VectorStore {
  // Create a new store
  constructor(dimension: number, metric: 'cosine' | 'euclidean' | 'dot' | 'hamming' | 'jaccard');
  
  // Create with storage mode (sq8/binary for memory optimization)
  static new_with_mode(dimension: number, metric: string, mode: 'full' | 'sq8' | 'binary'): VectorStore;
  
  // Create with pre-allocated capacity (performance optimization)
  static with_capacity(dimension: number, metric: string, capacity: number): VectorStore;

  // Properties
  readonly len: number;
  readonly is_empty: boolean;
  readonly dimension: number;
  readonly storage_mode: string;  // "full", "sq8", or "binary"

  // Methods
  insert(id: bigint, vector: Float32Array): void;
  insert_with_payload(id: bigint, vector: Float32Array, payload: object): void;
  insert_batch(batch: Array<[bigint, number[]]>): void;  // Bulk insert
  search(query: Float32Array, k: number): Array<[bigint, number]>;
  search_with_filter(query: Float32Array, k: number, filter: object): Array<{id, score, payload}>;
  text_search(query: string, k: number, field?: string): Array<{id, score, payload}>;
  get(id: bigint): {id, vector, payload} | null;
  remove(id: bigint): boolean;
  clear(): void;
  reserve(additional: number): void;  // Pre-allocate memory
  memory_usage(): number;  // Accurate for each storage mode
  
  //
  multi_query_search(vectors: Float32Array, num_vectors: number, k: number, strategy?: string, rrf_k?: number): Array<[bigint, number]>;
  hybrid_search(vector: Float32Array, text_query: string, k: number, vector_weight?: number): Array<{id, score, payload}>;
  batch_search(vectors: Float32Array, num_vectors: number, k: number): Array<Array<[bigint, number]>>;
  similarity_search(query: Float32Array, threshold: number, operator: string, k: number): Array<[bigint, number]>;
  query(query_vector: Float32Array, k: number): Array<{nodeId, vectorScore, graphScore, fusedScore, bindings, columnData}>;

  // Sparse search (inverted index, on VectorStore)
  sparse_insert(doc_id: bigint, indices: Uint32Array, values: Float32Array): void;
  sparse_search(indices: Uint32Array, values: Float32Array, k: number): Array<{doc_id, score}>;

  // Persistence
  save(db_name: string): Promise<void>;
  static load(db_name: string): Promise<VectorStore>;
  static delete_database(db_name: string): Promise<void>;
  export_to_bytes(): Uint8Array;
  static import_from_bytes(bytes: Uint8Array): VectorStore;

  // Metadata-only store
  static new_metadata_only(): VectorStore;
  readonly is_metadata_only: boolean;
}

Filter Format

// Equality filter
const filter = {
  condition: { type: "eq", field: "category", value: "tech" }
};

// Comparison filters
const filter = {
  condition: { type: "gt", field: "price", value: 100 }
};  // Also: gte, lt, lte, neq

// Logical operators
const filter = {
  condition: {
    type: "and",
    conditions: [
      { type: "eq", field: "category", value: "tech" },
      { type: "gt", field: "views", value: 1000 }
    ]
  }
};  // Also: or, not

Distance Metrics

| Metric | Description | Best For | |--------|-------------|----------| | cosine | Cosine similarity | Text embeddings (BERT, GPT) | | euclidean | L2 distance | Image features, spatial data | | dot | Dot product | Pre-normalized vectors | | hamming | Hamming distance | Binary vectors, fingerprints | | jaccard | Jaccard similarity | Set similarity, sparse vectors |

Storage Modes (Memory Optimization)

Reduce memory usage with quantization:

// Full precision (default) - best recall
const full = new VectorStore(768, 'cosine');

// SQ8: 4x memory reduction (~1% recall loss)
const sq8 = VectorStore.new_with_mode(768, 'cosine', 'sq8');

// Binary: 32x memory reduction (~5-10% recall loss)
const binary = VectorStore.new_with_mode(768, 'hamming', 'binary');

console.log(sq8.storage_mode);  // "sq8"

| Mode | Memory (768D) | Compression | Use Case | |------|---------------|-------------|----------| | full | 3080 bytes | 1x | Default, max precision | | sq8 | 784 bytes | 4x | Scale, RAM-constrained | | binary | 104 bytes | 32x | Edge, IoT, mobile PWA |

IndexedDB Persistence

Save and restore your vector store for offline-first applications with built-in async methods:

import init, { VectorStore } from '@wiscale/velesdb-wasm';

async function main() {
  await init();

  // Create and populate a store
  const store = new VectorStore(768, 'cosine');
  store.insert(1n, new Float32Array(768).fill(0.1));
  store.insert(2n, new Float32Array(768).fill(0.2));

  // Save to IndexedDB (single async call)
  await store.save('my-vectors-db');
  console.log('Saved!', store.len, 'vectors');

  // Later: Load from IndexedDB
  const restored = await VectorStore.load('my-vectors-db');
  console.log('Restored!', restored.len, 'vectors');

  // Clean up: Delete database
  await VectorStore.delete_database('my-vectors-db');
}

main();

Persistence API

class VectorStore {
  // Save to IndexedDB (async)
  save(db_name: string): Promise<void>;
  
  // Load from IndexedDB (async, static)
  static load(db_name: string): Promise<VectorStore>;
  
  // Delete IndexedDB database (async, static)
  static delete_database(db_name: string): Promise<void>;
  
  // Manual binary export/import (for localStorage, file download, etc.)
  export_to_bytes(): Uint8Array;
  static import_from_bytes(bytes: Uint8Array): VectorStore;
}

Binary Format

| Field | Size | Description | |-------|------|-------------| | Magic | 4 bytes | "VELS" | | Version | 1 byte | Format version (1) | | Dimension | 4 bytes | Vector dimension (u32 LE) | | Metric | 1 byte | 0=cosine, 1=euclidean, 2=dot | | Count | 8 bytes | Number of vectors (u64 LE) | | Vectors | variable | id (8B) + data (dim × 4B) each |

Performance

Ultra-fast serialization thanks to contiguous memory layout:

| Operation | 10k vectors (768D) | Throughput | |-----------|-------------------|------------| | Export | ~7 ms | 4479 MB/s | | Import | ~10 ms | 2943 MB/s |

Use Cases

  • Browser-based RAG - 100% client-side semantic search
  • Offline-first apps - Works without internet, persists to IndexedDB
  • Privacy-preserving AI - Data never leaves the browser
  • Electron/Tauri apps - Desktop AI without a server
  • PWA applications - Full offline support with service workers

⚠️ Limitations vs REST Backend

The WASM build is optimized for client-side use cases but has some limitations compared to the full REST server.

Feature Comparison

| Feature | WASM | REST Server | |---------|------|-------------| | Vector search (NEAR) | ✅ | ✅ | | Metadata filtering | ✅ | ✅ | | Hybrid search (vector + text) | ✅ | ✅ | | Full-text search | ✅ | ✅ | | Multi-query fusion (MQG) | ✅ | ✅ | | Batch search | ✅ | ✅ | | Sparse search | ✅ | ✅ | | Knowledge Graph (nodes, edges, traversal) | ✅ | ✅ | | Agent Memory (SemanticMemory) | ✅ | ✅ | | VelesQL parsing and validation | ✅ | ✅ | | VelesQL query execution | ❌ | ✅ | | Cross-collection MATCH (@collection) | ❌ | ✅ | | JOIN operations | ❌ | ✅ | | Aggregations (GROUP BY) | ❌ | ✅ | | Persistence | IndexedDB | Disk (mmap) | | Max vectors | ~100K (browser RAM) | Millions |

VelesQL (Parser Only)

VelesQL parsing and validation are available in WASM. You can parse queries, inspect their AST, and validate syntax client-side. However, query execution (running queries against data) requires the REST server.

import { VelesQL } from '@wiscale/velesdb-wasm';

// Parse and inspect a query
const parsed = VelesQL.parse("SELECT * FROM docs WHERE vector NEAR $v LIMIT 10");
console.log(parsed.tableName);       // "docs"
console.log(parsed.hasVectorSearch); // true
console.log(parsed.limit);          // 10

// Validate syntax
VelesQL.isValid("SELECT * FROM docs");        // true
VelesQL.isValid("SELEC * FROM docs");         // false

// Parse MATCH (graph) queries
const match = VelesQL.parse("MATCH (p:Person)-[:KNOWS]->(f:Person) RETURN f.name");
console.log(match.isMatch);              // true
console.log(match.matchNodeCount);       // 2
console.log(match.matchRelationshipCount); // 1

Knowledge Graph (GraphStore)

Build and traverse in-memory knowledge graphs entirely in the browser:

import { GraphStore, GraphNode, GraphEdge } from '@wiscale/velesdb-wasm';

const graph = new GraphStore();

// Create nodes
const alice = new GraphNode(1n, "Person");
alice.set_string_property("name", "Alice");
const bob = new GraphNode(2n, "Person");
bob.set_string_property("name", "Bob");

graph.add_node(alice);
graph.add_node(bob);

// Create edges
const edge = new GraphEdge(1n, 1n, 2n, "KNOWS");
graph.add_edge(edge);

// Traverse
const neighbors = graph.get_neighbors(1n);   // [2n]
const outgoing = graph.get_outgoing(1n);      // [GraphEdge]
const bfsResults = graph.bfs_traverse(1n, 3, 100); // BFS up to depth 3

Agent Memory (SemanticMemory)

Store and retrieve knowledge facts by semantic similarity for AI agent workloads:

import { SemanticMemory } from '@wiscale/velesdb-wasm';

const memory = new SemanticMemory(384);

// Store knowledge with embedding vectors
memory.store(1n, "Paris is the capital of France", embedding1);
memory.store(2n, "Berlin is the capital of Germany", embedding2);

// Query by similarity
const results = memory.query(queryEmbedding, 5);
// [{id, score, content}, ...]

console.log(memory.len());       // 2
console.log(memory.dimension()); // 384

Sparse Search (SparseIndex)

Inverted-index search with sparse vectors and RRF hybrid fusion:

import { SparseIndex, hybrid_search_fuse } from '@wiscale/velesdb-wasm';

const index = new SparseIndex();

// Insert sparse vectors (term indices + weights)
index.insert(1n, new Uint32Array([10, 20, 30]), new Float32Array([1.0, 0.5, 0.3]));
index.insert(2n, new Uint32Array([10, 40]),     new Float32Array([0.8, 1.2]));

// Search
const results = index.search(new Uint32Array([10, 20]), new Float32Array([1.0, 1.0]), 5);

// Fuse dense + sparse results with RRF
const fused = hybrid_search_fuse(denseResults, sparseResults, 60, 10);

When to Use REST Backend

Consider using the REST server if you need:

  • VelesQL query execution - Running queries against data (JOINs, aggregations, server-side filtering)
  • Cross-collection MATCH - The @collection annotation requires Database-level query routing, which is only available on the server (WASM operates on a single collection)
  • Large datasets - More than 100K vectors
  • Server-side processing - Centralized vector database

Migration from WASM to REST

// WASM (client-side)
import { VectorStore } from '@wiscale/velesdb-wasm';
const store = new VectorStore(768, 'cosine');
const results = store.search(query, 10);

// REST (server-side) - using fetch
const response = await fetch('http://localhost:8080/collections/docs/search', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ vector: query, top_k: 10 })
});
const results = await response.json();

// REST with VelesQL
const response = await fetch('http://localhost:8080/query', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: "SELECT * FROM docs WHERE vector NEAR $v AND category = 'tech' LIMIT 10",
    params: { v: query }
  })
});

Building from Source

# Install wasm-pack
cargo install wasm-pack

# Build for browser
wasm-pack build --target web

# Build for Node.js
wasm-pack build --target nodejs

Performance

Typical latencies on modern browsers:

| Operation | 768D vectors | 10K vectors | |-----------|--------------|-------------| | Insert | ~1 µs | ~10 ms | | Search | ~50 µs | ~5 ms |

License

MIT License (bindings). The core engine (velesdb-core and velesdb-server) is under VelesDB Core License 1.0.

See LICENSE for WASM bindings license, root LICENSE for core engine.