How VelesDB WASM Integration Works for Browser-Based Applications

VelesDB delivers browser-based vector search through a wasm-bindgen compiled Rust core, wrapped by a TypeScript SDK that dynamically loads the module and exposes the VectorStore class for client-side CRUD and similarity search operations.

The cyberlife-coder/velesdb repository ships a dedicated WebAssembly build via the velesdb-wasm crate, enabling the core vector-store engine to run entirely within browsers or Node.js. This integration eliminates server dependencies by compiling the Rust search algorithms to WASM and exposing them through idiomatic JavaScript APIs.

Architecture of the WASM Integration

The system operates through three tightly-coupled layers that bridge Rust and JavaScript:

Layer Purpose Key File
WASM Binary Compiled Rust code exposing vector operations via wasm-bindgen crates/velesdb-wasm/src/lib.rs
JavaScript Glue Dynamic module loading and VectorStore class re-export sdks/typescript/src/backends/wasm.ts
Demo & SDK HTML examples and TypeScript wrappers for CDN distribution examples/wasm-browser-demo/README.md

Loading the WASM Module in the Browser

Browser applications load the compiled binary directly from npm CDNs. The entry point calls init(), which resolves the velesdb_wasm_bg.wasm file, allocates linear memory, and registers exported Rust functions as JavaScript methods.

In crates/velesdb-wasm/src/lib.rs, the #[wasm_bindgen(start)] attribute marks the init function as the module entry point. When invoked, it instantiates the WASM blob and prepares the runtime for VectorStore operations.

<script type="module">
  // Pull the module from a CDN (unpkg or jsdelivr)
  import init, { VectorStore } from
    'https://unpkg.com/velesdb-wasm@latest/velesdb_wasm.js';

  // Initialise the Wasm runtime
  await init();

  // Use the exported class
  const store = new VectorStore(768, 'cosine');
</script>

The TypeScript SDK mirrors this flow in sdks/typescript/src/backends/wasm.ts by performing a dynamic import('@wiscale/velesdb-wasm') when a VelesDB instance is created with backend: 'wasm'.

The VectorStore Core Implementation

The Rust side defines the VectorStore struct (lines 97-129 of lib.rs) to store vectors in a contiguous Vec<f32> buffer for the default Full mode, while also supporting compressed SQ8 and Binary modes to reduce memory footprint.

Key methods exposed to JavaScript via #[wasm_bindgen] include:

Method Description
new(dimension, metric) Creates an empty store with specified distance metric
insert(id, vector) Adds a single vector using u64/BigInt IDs
insert_batch(batch) Fast bulk insertion to minimize JS-to-WASM call overhead
search(query, k) Returns the k nearest neighbours with IDs and scores
search_with_filter(query, k, filter) Applies JSON payload filtering during the search
text_search(query, k, field?) Substring search across payload fields
save(db_name) / load(db_name) Persists to IndexedDB via persistence.rs (lines 77-95)
export_to_bytes() / import_from_bytes() Serializes the store for manual storage in localStorage

These methods are thin wrappers around internal Rust modules such as store_insert, store_search, and serialization within the impl VectorStore block.

TypeScript SDK Backend Integration

When an application initializes the SDK with backend: 'wasm', the WasmBackend class orchestrates the loading sequence (lines 57-61 of wasm.ts):

  1. Calls WasmBackend.init() to trigger the dynamic import
  2. Resolves the @wiscale/velesdb-wasm npm package
  3. Executes the default export to run the wasm-bindgen generated init() function
  4. Stores the module reference and initializes the backend flag

All subsequent operations (createCollection, insert, search) delegate to the VectorStore instance held in the collections map (see createCollection at lines 80-96). The SDK handles ID conversion between numeric Rust IDs and string JavaScript IDs while maintaining payload bookkeeping.

import { VelesDB } from '@wiscale/velesdb';

async function run() {
  const db = new VelesDB({ backend: 'wasm' });
  await db.init();                     // loads the WASM module
  await db.createCollection('docs', { dimension: 256 });

  // Insert with payload
  await db.insert('docs', {
    id: 'doc-1',
    vector: new Float32Array(256).map(() => Math.random()),
    payload: { title: 'Hello', tags: ['demo'] },
  });

  // Vector search
  const results = await db.search('docs', new Float32Array(256).map(() => Math.random()), { k: 5 });
  console.log(results);
}
run();

Client-Side Persistence with IndexedDB

The WASM store runs entirely in memory, but the crate ships IndexedDB helpers for offline-first applications. The save and load methods (exposed via #[wasm_bindgen] in lib.rs lines 77-95 and implemented in persistence.rs) serialize the vector data to browser storage.

import { VelesDB } from '@wiscale/velesdb';

async function demoPersist() {
  const db = new VelesDB({ backend: 'wasm' });
  await db.init();
  await db.createCollection('mem', { dimension: 64 });

  // ... insert data ...

  // Persist to IndexedDB
  const collection = await db.getCollection('mem');
  await collection?.backend?.save('my-vectors-db');
  
  // Restore in a later session
  const restored = await VectorStore.load('my-vectors-db');
}

This enables Progressive Web Apps to cache semantic-search indexes on first load and run vector queries without network connectivity.

Performance and Bundle Optimization

The velesdb-wasm crate optimizes for browser constraints through several mechanisms:

  • SIMD Vectorization: Built with wasm-pack --target web and --enable-simd flags to ensure distance calculations leverage browser SIMD support
  • Batch Insertion: The insert_batch method reduces JavaScript-to-WebAssembly context switching overhead compared to individual inserts
  • Tree-Shaking: Importing only the VectorStore class keeps the gzipped bundle under 200KB, as documented in docs/wasm/bundle-optimization.md
  • Lazy Loading: The TypeScript SDK dynamically imports the WASM module only when backend: 'wasm' is specified, preventing unnecessary payload costs for REST-only applications

Summary

  • VelesDB compiles its core Rust vector engine to WebAssembly via wasm-bindgen, exposing the VectorStore class directly to browser JavaScript.
  • The TypeScript SDK dynamically loads the @wiscale/velesdb-wasm package and routes all CRUD and search operations through the Rust-backed VectorStore.
  • Client-side persistence uses IndexedDB through the save() and load() methods implemented in persistence.rs, supporting offline-first use cases.
  • SIMD instructions and batch insertion APIs maximize query performance while keeping the bundle size below 200KB gzipped.

Frequently Asked Questions

Which browsers support VelesDB's WASM integration?

VelesDB requires a WebAssembly runtime with SIMD support for optimal performance, which is available in all modern browsers including Chrome, Firefox, Safari, and Edge. The build process uses wasm-pack --target web with --enable-simd to ensure vectorized distance calculations function correctly across supported environments.

How large is the WASM bundle for production deployment?

The gzipped bundle size remains under 200KB when tree-shaking is applied to import only the VectorStore class. The documentation in docs/wasm/bundle-optimization.md provides specific guidelines for minimizing payload size through compression mode selection and lazy loading patterns.

Can VelesDB WASM persist data between browser sessions?

Yes, the VectorStore class provides save(db_name) and load(db_name) methods that serialize the entire store to IndexedDB. This persistence layer is implemented in crates/velesdb-wasm/src/persistence.rs and exposed via #[wasm_bindgen], allowing applications to maintain semantic search indexes offline between sessions.

What is the difference between the WASM backend and the REST backend?

The WASM backend (backend: 'wasm') executes vector search entirely within browser memory using the compiled Rust core, while the REST backend communicates with a remote VelesDB server. The WASM approach eliminates network latency and enables offline operation but is constrained by browser memory limits, whereas the REST backend handles larger datasets server-side with persistent storage.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →