Vecal

Installation

Install Vecal and configure its module Worker.

Installation

Install the release candidate from npm:

npm install vecal@1.0.0-rc.1
# or
yarn add vecal@1.0.0-rc.1

Vecal is ESM-only and has no runtime dependencies.

Open a database

import { VectorDB } from 'vecal';

const db = await VectorDB.open({
    name: 'documents',
    dimension: 384,
    metric: 'cosine',
});
OptionRequiredMeaning
nameYesLogical database name. Its physical IndexedDB name is vecal:${name}:v1.
dimensionYesPositive integer length required for every stored and query vector.
metricYesStable database metric: cosine, l2, or dot.
workerUrlNoOverride the adjacent dist/worker.js module URL.
workerFactoryNoCreate a Worker-like object for CSP, bundler, or test integration.

The name, dimension, and metric are durable schema. Reopening the same name with a different dimension or metric throws SchemaMismatchError; 0.0.1 databases are not migrated.

Worker and CSP

By default, Vecal uses the standard package-relative form:

new Worker(new URL('./worker.js', import.meta.url), {
    type: 'module',
    name: 'vecal:documents',
});

If your Content Security Policy needs an explicit asset URL, deploy the emitted Worker module together with its adjacent internal modules:

const db = await VectorDB.open({
    name: 'documents',
    dimension: 384,
    metric: 'cosine',
    workerUrl: new URL('/vecal/dist/worker.js', location.origin),
});

Or let your application bundler compile an app-local Worker entry:

const db = await VectorDB.open({
    name: 'documents',
    dimension: 384,
    metric: 'cosine',
    workerFactory: () =>
        new Worker(new URL('./vecal.worker.ts', import.meta.url), { type: 'module' }),
});
vecal.worker.ts
import { startVecalWorker } from 'vecal/worker';

startVecalWorker();

Serve Worker modules with JavaScript MIME type and allow their origin in worker-src. Vecal intentionally has no main-thread storage/search fallback: if the Worker cannot start, open() fails.

SSR frameworks

The package can be imported on a server, but only call VectorDB.open() from a client component, effect, browser event, or other client-only path.

'use client';

import { useEffect } from 'react';
import { VectorDB } from 'vecal';

export function SearchClient() {
    useEffect(() => {
        let disposed = false;
        let database: Awaited<ReturnType<typeof VectorDB.open>> | undefined;

        void VectorDB.open({ name: 'search', dimension: 384, metric: 'cosine' }).then((db) => {
            if (disposed) void db.close();
            else database = db;
        });

        return () => {
            disposed = true;
            void database?.close();
        };
    }, []);

    return null;
}

Compatibility

Vecal supports the latest two releases of Chrome, Firefox, and Safari. It requires IndexedDB, Dedicated Workers, module Workers, structured clone, BroadcastChannel for fast cross-tab notification, and crypto.randomUUID() for generated IDs. Authoritative revision checks still protect operation-boundary consistency when a notification is delayed.