LocalMode
Core

Vector Database

Create, query, and persist vector databases with HNSW indexing.

LocalMode includes a high-performance vector database with HNSW (Hierarchical Navigable Small World) indexing for fast approximate nearest neighbor search.

Creating a Database

import { createVectorDB } from '@localmode/core';

const db = await createVectorDB({
  name: 'my-documents',
  dimensions: 384, // Must match your embedding model
});

VectorDBConfig

Prop

Type

With Custom Storage

import { createVectorDB, MemoryStorage } from '@localmode/core';

// Use memory storage (no persistence)
const db = await createVectorDB({
  name: 'temp-db',
  dimensions: 384,
  storage: new MemoryStorage(),
});

// Or use a third-party adapter
import { DexieStorage } from '@localmode/dexie';

const db = await createVectorDB({
  name: 'dexie-db',
  dimensions: 384,
  storage: new DexieStorage({ name: 'my-app' }),
});

Adding Documents

Single Document

await db.add({
  id: 'doc-1',
  vector: embedding, // Float32Array
  metadata: {
    text: 'Original document text',
    source: 'file.pdf',
    page: 1,
  },
});

Multiple Documents

await db.addMany([
  { id: 'doc-1', vector: embeddings[0], metadata: { text: 'First' } },
  { id: 'doc-2', vector: embeddings[1], metadata: { text: 'Second' } },
  { id: 'doc-3', vector: embeddings[2], metadata: { text: 'Third' } },
]);

Dimension Mismatch

The vector dimensions must match the dimensions specified when creating the database. Using a different size will throw a DimensionMismatchError.

Searching

const results = await db.search(queryVector, { k: 5 });

results.forEach((result) => {
  console.log(`ID: ${result.id}`);
  console.log(`Score: ${result.score.toFixed(4)}`);
  console.log(`Metadata:`, result.metadata);
});

With Filters

Filter results by metadata:

const results = await db.search(queryVector, {
  k: 10,
  filter: {
    source: { $eq: 'manual.pdf' },
  },
});

Filter Operators

Updating Documents

// Update metadata only (vector unchanged)
await db.update('doc-1', {
  metadata: { ...existingMetadata, status: 'reviewed' },
});

// Update vector and metadata
await db.update('doc-1', {
  vector: newEmbedding,
  metadata: { text: 'Updated text' },
});

Deleting Documents

// Delete single document
await db.delete('doc-1');

// Delete multiple documents
await db.deleteMany(['doc-1', 'doc-2', 'doc-3']);

// Clear all documents
await db.clear();

Delete by Filter

Delete documents matching a metadata filter:

// Delete all documents with a specific documentId
const deletedCount = await db.deleteWhere({
  documentId: 'doc-123',
});

console.log(`Deleted ${deletedCount} documents`);

// Delete documents matching multiple criteria
const count = await db.deleteWhere({
  $and: [
    { source: { $eq: 'old-import.pdf' } },
    { status: { $eq: 'archived' } },
  ],
});

Batch Deletion

Use deleteWhere() when you need to remove multiple documents by metadata (e.g., all chunks from a specific file). It's more efficient than deleting documents one by one.

Getting Documents

// Get by ID
const doc = await db.get('doc-1');
if (doc) {
  console.log(doc.id, doc.vector, doc.metadata);
}

// Check if exists
const exists = await db.has('doc-1');

// Get all IDs
const ids = await db.keys();

// Get count
const count = await db.size();

Persistence

By default, the vector database uses IndexedDB for persistence:

const db = await createVectorDB({
  name: 'persistent-db',
  dimensions: 384,
});

// Add documents
await db.addMany(documents);

// Data persists across page reloads!
// On next load, just create with same name:
const db2 = await createVectorDB({
  name: 'persistent-db', // Same name
  dimensions: 384,
});

// All documents are still there
const count = await db2.size();

Memory-Only Mode

For temporary data or testing:

import { MemoryStorage } from '@localmode/core';

const db = await createVectorDB({
  name: 'temp',
  dimensions: 384,
  storage: new MemoryStorage(),
});

// Data lost on page reload

Web Worker Mode

Offload database operations to a Web Worker for better main thread performance:

import { createVectorDBWithWorker } from '@localmode/core';

const db = await createVectorDBWithWorker({
  name: 'worker-db',
  dimensions: 384,
});

// Same API, but operations run in a worker
const results = await db.search(queryVector, { k: 5 });

Worker Benefits

Worker mode prevents blocking the main thread during: - Large batch insertions - Complex searches

  • Index rebuilding

HNSW Configuration

Tune the HNSW index for your use case:

const db = await createVectorDB({
  name: 'tuned-db',
  dimensions: 384,
  hnswConfig: {
    // More connections = better accuracy, more memory
    m: 32, // Default: 16

    // Higher = better index quality, slower builds
    efConstruction: 400, // Default: 200

    // Higher = better search accuracy, slower searches
    efSearch: 100, // Default: 50
  },
});

Configuration Guidelines

Use CasemefConstructionefSearch
Fast, low memory810030
Balanced (default)1620050
High accuracy32400100
Maximum accuracy48500200

Middleware

Add middleware for logging, encryption, etc.:

import { wrapVectorDB, loggingMiddleware } from '@localmode/core';

const baseDB = await createVectorDB({ name: 'db', dimensions: 384 });

const db = wrapVectorDB(baseDB, {
  beforeSearch: async (vector, options) => {
    console.log('Searching with k =', options.k);
    return { vector, options };
  },
  afterSearch: async (results) => {
    console.log('Found', results.length, 'results');
    return results;
  },
});

Type Safety

Full TypeScript support for metadata:

interface MyMetadata {
  text: string;
  source: string;
  page: number;
  tags: string[];
}

const db = await createVectorDB<MyMetadata>({
  name: 'typed-db',
  dimensions: 384,
});

// Type-safe add
await db.add({
  id: 'doc-1',
  vector: embedding,
  metadata: {
    text: 'Hello',
    source: 'file.pdf',
    page: 1,
    tags: ['intro'],
  },
});

// Type-safe search results
const results = await db.search(queryVector, { k: 5 });
results.forEach((r) => {
  // r.metadata is typed as MyMetadata
  console.log(r.metadata.text);
});

Next Steps

On this page