Skip to main content

Node.js API Reference

Complete reference for the vectlite npm package.

const vectlite = require('vectlite')
// or
import * as vectlite from 'vectlite'

Module Functions

open

function open(path: string, options?: OpenOptions): Database

Open or create a vectlite database.

ParameterTypeDescription
pathstringPath to the .vdb file. Created if it does not exist.
optionsOpenOptionsOptional configuration.

OpenOptions

PropertyTypeDefaultDescription
dimensionnumber--Vector dimension. Required when creating a new database.
metricstring'cosine'Distance metric used at creation time. One of 'cosine', 'euclidean' (alias 'l2'), 'dotproduct' (aliases 'dot', 'ip', 'inner_product', 'dot_product'), or 'manhattan' (alias 'l1'). Persisted in the database file. Ignored when opening an existing database. Scores are always oriented so higher is better.
readOnlybooleanfalseOpen in read-only mode.
lockTimeoutnumber--Maximum seconds to wait when acquiring the advisory file lock. Omit to fail immediately on contention.

Returns: Database


openStore

function openStore(root: string): Store

Open or create a collection store directory.

ParameterTypeDescription
rootstringPath to the store directory.

Returns: Store


restore

function restore(source: string, dest: string): Database

Restore a backup to a new database path.

ParameterTypeDescription
sourcestringPath to the backup directory.
deststringPath for the restored .vdb file.

Returns: Database


sparseTerms

function sparseTerms(text: string): SparseVector

Tokenize and weight text into a sparse term vector for BM25 search.

ParameterTypeDescription
textstringInput text.

Returns: SparseVector (Record<string, number>)


upsertText

function upsertText(
db: Database,
id: string,
text: string,
embed: (text: string) => number[] | Promise<number[]>,
metadata?: Metadata,
options?: { namespace?: string }
): void | Promise<void>

High-level helper that generates a dense embedding and sparse terms from text, then upserts the record. If embed returns a Promise, the function is async.

ParameterTypeDescription
dbDatabaseTarget database.
idstringRecord identifier.
textstringText to embed and index.
embed(text: string) => number[] | Promise<number[]>Embedding function.
metadataMetadataOptional metadata object.
options.namespacestringOptional namespace.

searchText

function searchText(
db: Database,
text: string,
embed: (text: string) => number[] | Promise<number[]>,
options?: SearchOptions
): SearchResult[] | Promise<SearchResult[]>

High-level hybrid search. Generates a dense embedding and sparse terms from text, then runs a fused search. Async if embed returns a Promise.

ParameterTypeDescription
dbDatabaseTarget database.
textstringNatural-language query.
embed(text: string) => number[] | Promise<number[]>Embedding function.
optionsSearchOptionsSearch configuration (see SearchOptions).

Returns: SearchResult[]


searchTextWithStats

function searchTextWithStats(
db: Database,
text: string,
embed: (text: string) => number[] | Promise<number[]>,
options?: SearchOptions
): SearchResponse | Promise<SearchResponse>

Same as searchText but returns a SearchResponse with results and query statistics.


configureOpenTelemetry

function configureOpenTelemetry(
config?: boolean | {
tracer?: unknown
tracerName?: string
enabled?: boolean
}
): unknown

Enable, disable, or configure optional OpenTelemetry tracing for search operations. When active, every searchText() and searchTextWithStats() call is wrapped in a vectlite.search span carrying db.system, db.operation.name, and search-specific attributes (vectlite.search.k, .namespace, .has_dense, .has_sparse, .fusion, .used_ann, .result_count, .total_us).

@opentelemetry/api is loaded lazily and is not a runtime dependency. If a search throws, the span records the exception and sets an error status before re-throwing.

FormBehaviour
configureOpenTelemetry()Auto-detect: resolves a tracer from @opentelemetry/api if installed.
configureOpenTelemetry({ tracer: myTracer })Use a user-supplied tracer instance.
configureOpenTelemetry({ tracerName: 'my-app' })Override the tracer name (default 'vectlite').
configureOpenTelemetry({ enabled: false }) or configureOpenTelemetry(false)Disable tracing.

Returns: the active tracer (or null when disabled).


Database

Returned by open() and restore().

Properties

PropertyTypeDescription
pathstringAbsolute path to the .vdb file.
walPathstringPath to the write-ahead log file.
dimensionnumberVector dimension.
metricstringDistance metric: 'cosine', 'euclidean', 'dotproduct', or 'manhattan'.
readOnlybooleanWhether opened in read-only mode.
quantizationMethodstring | nullActive quantization method ('scalar', 'binary', 'product') or null.
Property vs method

quantizationMethod is a property. Use db.isQuantized() as a method to check whether quantization is enabled.

count

count(options?: { namespace?: string; filter?: Filter }): number

Return the number of records, optionally scoped by namespace and/or filter.

namespaces

namespaces(): string[]

Return all namespace names.

transaction

transaction(): Transaction

Begin a new transaction.

Returns: Transaction

insert

insert(
id: string,
vector: number[],
metadata?: Metadata,
options?: WriteOptions
): void

Insert a new record. Throws VectLiteError if the ID already exists.

upsert

upsert(
id: string,
vector: number[],
metadata?: Metadata,
options?: WriteOptions
): void

Insert or replace a record.

WriteOptions

PropertyTypeDescription
namespacestringTarget namespace.
sparseSparseVectorSparse term vector for BM25.
vectorsNamedVectorsAdditional named vectors.
ttlnumberTime-to-live in seconds. Expired records are filtered from reads and garbage-collected on compact().

insertMany

insertMany(records: Record[], options?: { namespace?: string }): number

Batch insert. Returns the number of records inserted.

upsertMany

upsertMany(records: Record[], options?: { namespace?: string }): number

Batch upsert. Returns the number of records upserted.

bulkIngest

bulkIngest(
records: Record[],
options?: BulkIngestOptions
): number

Ingest a batch of records efficiently.

BulkIngestOptions

PropertyTypeDefaultDescription
namespacestring--Target namespace.
batchSizenumber10000Internal WAL batch size.

Returns: number -- total records ingested.

get

get(id: string, options?: { namespace?: string }): Record | null

Retrieve a record by ID. Returns null if not found.

delete

delete(id: string, options?: { namespace?: string }): boolean

Delete a record. Returns true if the record existed.

deleteMany

deleteMany(ids: string[], options?: { namespace?: string }): number

Delete multiple records. Returns the count of records deleted.

deleteByFilter

deleteByFilter(filter: Filter, options?: { namespace?: string }): number

Delete every record that matches filter in a single pass. Returns the number of records deleted.

const deleted = db.deleteByFilter({ stale: true }, { namespace: 'docs' })

updateMetadata

updateMetadata(
id: string,
metadata: Metadata,
options?: { namespace?: string }
): boolean

Merge a metadata patch into an existing record without re-writing the vector. Keys present in metadata overwrite existing keys; other keys are left untouched. Skips ANN, sparse, quantized, and multi-vector index rebuilds when a WAL batch contains only metadata updates.

Returns true if the record was found and updated.

db.updateMetadata('doc1', { status: 'reviewed', score: 0.95 })

list

list(options?: {
namespace?: string
filter?: Filter
limit?: number // 0 = no limit
offset?: number
}): Record[]

List records without issuing a vector query.

listCursor

listCursor(options?: {
namespace?: string
filter?: Filter
limit?: number // default: 100
cursor?: string | null
}): { records: Record[]; cursor: string | null }

Cursor-based pagination for efficient iteration over large collections. cursor is null when the iterator is exhausted.

let cursor = null
do {
const page = db.listCursor({ limit: 100, cursor })
for (const record of page.records) process(record)
cursor = page.cursor
} while (cursor)

setTtl

setTtl(
id: string,
ttlSecs: number,
options?: { namespace?: string }
): boolean

Set a time-to-live (in seconds from now) on an existing record. Expired records are transparently filtered from get(), list(), count(), and search(), and are permanently removed on compact(). The expiresAt field on Record exposes the absolute expiry timestamp (epoch seconds).

clearTtl

clearTtl(id: string, options?: { namespace?: string }): boolean

Remove the expiry from a record so it lives indefinitely.

createIndex

createIndex(field: string, indexType: 'keyword' | 'numeric'): void

Create a payload index on a metadata field to accelerate filtered queries 10-100x on large collections. Indexes are automatically used by search(), count(), and list() to narrow candidates before full filter evaluation. AND filters intersect index results; OR filters union when all sub-filters are indexed. Index definitions persist across close/reopen in a .vdb.pidx sidecar file.

db.createIndex('source', 'keyword')   // string equality, $in
db.createIndex('score', 'numeric') // range queries: $gt, $gte, $lt, $lte

dropIndex

dropIndex(field: string): boolean

Remove a payload index. Returns true if the index existed.

listIndexes

listIndexes(): Array<[string, string]>

Return all active payload indexes as [field, indexType] tuples.

enableQuantization

enableQuantization(
method: 'scalar' | 'binary' | 'product' | 'pq',
options?: {
rescoreMultiplier?: number // default: 4 — fetches k × rescoreMultiplier candidates
numSubVectors?: number // PQ only; omit for a dimension-aware default
numCentroids?: number // PQ only, default: 256
}
): void

Enable vector quantization to reduce memory and accelerate search. All methods use a 2-stage pipeline: fast quantized candidate selection followed by exact float32 rescoring. Parameters persist in a .vdb.quant sidecar file and reload automatically on open. Indexes rebuild automatically on inserts, upserts, and bulk ingestion. Method names are parsed case-insensitively.

MethodCompressionNotes
scalar~4x (int8)Minimal recall loss.
binary~32xBest for normalized embeddings (Hamming distance filtering).
product / pqconfigurablek-means PQ for very large datasets.
db.enableQuantization('scalar')
db.enableQuantization('binary', { rescoreMultiplier: 10 })
db.enableQuantization('pq') // dimension-aware default for numSubVectors
db.enableQuantization('product', { numSubVectors: 16, numCentroids: 256 })

disableQuantization

disableQuantization(): void

Disable quantization and remove the persisted .vdb.quant sidecar.

isQuantized

isQuantized(): boolean

Whether vector quantization is currently enabled. Method, not a property since 0.9.1.

validNumSubVectors

validNumSubVectors(): number[]

Return the list of valid numSubVectors values for this database's dimension (i.e. the divisors that allow an even split). Useful before calling enableQuantization('pq', { numSubVectors: ... }).

upsertMultiVectors

upsertMultiVectors(
id: string,
vector: number[],
multiVectors: Record<string, number[][]>,
metadata?: Metadata,
options?: { namespace?: string; sparse?: SparseVector }
): void

Insert or replace a record carrying per-token (ColBERT, ColPali) embeddings for late-interaction search. vector is the usual dense embedding; multiVectors maps space names to a list of token vectors.

db.upsertMultiVectors(
'doc1',
denseVector,
{ colbert: [tokenVec1, tokenVec2 /* ... */] },
{ source: 'paper' }
)

searchMultiVector

searchMultiVector(
space: string,
queryTokens: number[][],
options?: {
k?: number
namespace?: string
filter?: Filter
}
): SearchResult[]

MaxSim late-interaction search: for each query token, take the max cosine similarity against all document tokens, then sum across query tokens.

enableMultiVectorQuantization

enableMultiVectorQuantization(space: string): void

Enable ColBERTv2-style 2-bit quantization (~16x compression) for a multi-vector space. Parameters persist in a .vdb.mvquant.<space> sidecar file.

disableMultiVectorQuantization

disableMultiVectorQuantization(space: string): void

Disable 2-bit quantization for a multi-vector space.

isMultiVectorQuantized

isMultiVectorQuantized(space: string): boolean

Whether a multi-vector space currently has 2-bit quantization enabled.

close

close(): void

Flush pending state, release the file lock, and invalidate the handle. Subsequent operations that return data throw VectLiteError.

Async methods

Non-blocking versions of heavy operations, scheduled on the libuv threadpool via napi::Task (no tokio dependency). Use them in hot HTTP paths to avoid stalling the event loop.

db.searchAsync(vector: number[] | null, options?: SearchOptions): Promise<SearchResult[]>
db.searchWithStatsAsync(vector: number[] | null, options?: SearchOptions): Promise<SearchResponse>
db.bulkIngestAsync(records: Record[], options?: BulkIngestOptions): Promise<number>
db.flushAsync(): Promise<void>
db.compactAsync(): Promise<void>
const results = await db.searchAsync(queryVector, { k: 10, filter: { source: 'blog' } })

flush

flush(): void

Alias for compact() in the current package.

compact

compact(): void

Merge WAL into the main .vdb file and rebuild ANN indexes as needed.

snapshot

snapshot(dest: string): void

Create a self-contained database copy at dest.

backup

backup(dest: string): void

Full backup of .vdb and ANN sidecar files to dest directory.

search(
vector: number[] | null,
options?: SearchOptions
): SearchResult[]

// Shorthand: second arg is k (since 0.9.2)
search(vector: number[] | null, k: number): SearchResult[]

// Single-object form (since 0.9.1)
search(options: SearchOptions & { query: number[] | null }): SearchResult[]

Run a search query. Pass null as the vector for sparse-only or multi-vector search.

// Positional form
db.search(queryVector, { k: 10, filter: { source: 'blog' } })

// Shorthand — second arg is k (since 0.9.2)
db.search(queryVector, 10)

// Single-object form (since 0.9.1)
db.search({ query: queryVector, k: 10, filter: { source: 'blog' } })

All three forms are also supported by searchWithStats, searchAsync, and searchWithStatsAsync.

Strict dimension matching (changed in 0.9.1)

Search now rejects query vectors whose length does not match the database dimension, returning DimensionMismatch. Previously, undersized queries were silently truncated via Matryoshka logic. To opt into prefix search, pass truncateDim in the options. An all-zeros vector also raises an error for cosine / dot-product metrics.

Returns: SearchResult[]

searchWithStats

searchWithStats(
vector: number[] | null,
options?: SearchOptions
): SearchResponse

Same as search() but returns a SearchResponse.


Store

Returned by openStore(). Manages a directory of collections.

Properties

PropertyTypeDescription
rootstringAbsolute path to the store directory.

collections

collections(): string[]

List all collection names.

createCollection

createCollection(name: string, dimension: number): Database

Create a new collection. Throws if it already exists.

openOrCreateCollection

openOrCreateCollection(name: string, dimension: number): Database

Open or create a collection.

openCollection

openCollection(name: string): Database

Open an existing collection. Throws if it does not exist.

dropCollection

dropCollection(name: string): boolean

Delete a collection and its data from disk. Returns true if it existed.

close

close(): void

Symmetry with Database.close(). The store holds no open file handles, so this is currently a no-op, but using it future-proofs your code across binding versions. Available since 0.9.1.


Transaction

Returned by Database.transaction(). Node.js does not have a with statement, so you must call commit() or rollback() manually.

const tx = db.transaction()
try {
tx.upsert('doc1', emb1, { source: 'a' })
tx.delete('old_doc')
tx.commit()
} catch (err) {
tx.rollback()
throw err
}

insert

insert(
id: string,
vector: number[],
metadata?: Metadata,
options?: WriteOptions
): void

upsert

upsert(
id: string,
vector: number[],
metadata?: Metadata,
options?: WriteOptions
): void

insertMany

insertMany(records: Record[], options?: { namespace?: string }): number

upsertMany

upsertMany(records: Record[], options?: { namespace?: string }): number

delete

delete(id: string, options?: { namespace?: string }): boolean

commit

commit(): void

Commit all queued operations atomically.

rollback

rollback(): void

Discard all queued operations.

count

count(): number

Number of queued operations in the transaction.


Interfaces

OpenOptions

interface OpenOptions {
dimension?: number
readOnly?: boolean
}

WriteOptions

interface WriteOptions {
namespace?: string
sparse?: SparseVector
vectors?: NamedVectors
}

SearchOptions

interface SearchOptions {
k?: number // default: 10
filter?: Filter
namespace?: string
allNamespaces?: boolean // default: false
sparse?: SparseVector
denseWeight?: number // default: 1.0
sparseWeight?: number // default: 1.0
fetchK?: number // default: 0
mmrLambda?: number
vectorName?: string
fusion?: 'linear' | 'rrf' // default: 'linear'
rrfK?: number // default: 60
queryVectors?: NamedVectors
vectorWeights?: Record<string, number>
explain?: boolean // default: false
truncateDim?: number // Matryoshka prefix search
}

truncateDim enables Matryoshka prefix search: query and database vectors are truncated to the first truncateDim dimensions before scoring. Required when the query length is shorter than the database dimension; otherwise the engine throws DimensionMismatch.

BulkIngestOptions

interface BulkIngestOptions {
namespace?: string
batchSize?: number // default: 10000
}

Record

interface Record {
namespace: string
id: string
vector: number[]
vectors: NamedVectors
multiVectors?: Record<string, number[][]>
sparse: SparseVector
metadata: Metadata
expiresAt?: number | null // epoch seconds (TTL)
}

expiresAt is the absolute expiry timestamp in epoch seconds when a TTL is set (otherwise null).

SearchResult

interface SearchResult {
namespace: string
id: string
score: number
dense_score: number
sparse_score: number
vector_name: string | null
matched_terms: string[]
dense_rank: number | null
sparse_rank: number | null
metadata: Metadata
bm25_term_scores: Record<string, number>
explain?: ExplainDetails
}

ExplainDetails

interface ExplainDetails {
fusion?: string
dense_score?: number
sparse_score?: number
matched_terms?: string[]
vector_name?: string | null
dense_rank?: number | null
sparse_rank?: number | null
bm25_term_scores?: Record<string, number>
}

SearchStats

interface SearchStats {
used_ann: boolean
ann_candidate_count: number
exact_fallback: boolean
considered_count: number
fetch_k: number
mmr_applied: boolean
sparse_candidate_count: number
ann_loaded_from_disk: boolean
wal_entries_replayed: number
fusion: string
rerank_applied: boolean
rerank_count: number
timings: SearchTimings
}

SearchTimings

interface SearchTimings {
dense_us: number
sparse_us: number
fusion_us: number
total_us: number
}

SearchResponse

interface SearchResponse {
results: SearchResult[]
stats: SearchStats
}

MetadataValue

type MetadataValue = string | number | boolean | null | MetadataValue[] | { [key: string]: MetadataValue }

Metadata

type Metadata = Record<string, MetadataValue>

SparseVector

type SparseVector = Record<string, number>

NamedVectors

type NamedVectors = Record<string, number[]>

Filter

type Filter = Record<string, any>

MongoDB-style filter expression. See Metadata Filters for the full query syntax.


Error

VectLiteError

class VectLiteError extends Error {
constructor(message: string)
}

Thrown for all vectlite errors including:

  • Write operations on a read-only database
  • Duplicate ID on insert()
  • Dimension mismatch
  • Corrupt database file
  • File lock contention
  • I/O errors