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

@monlite/vector

v0.6.3

Published

Vector / semantic search for monlite — sqlite-vec on @monlite/core, native pgvector on @monlite/postgres. Adds collection.findSimilar().

Readme

@monlite/vector

Vector / semantic search for monlite — RAG and AI-agent memory. Adds collection.findSimilar(), the same API on either engine:

  • SQLite (@monlite/core) — powered by sqlite-vec (with a brute-force JS fallback), all in your local .db. Index maintained on every write, including @monlite/sync changes.
  • Postgres (@monlite/postgres) — a native generated vector(dim) column + HNSW index (pgvector), maintained by Postgres itself.

A monlite plugin. Store documents with an embedding field, search by nearest neighbour.

import { createDb } from "@monlite/core";
import { vector } from "@monlite/vector";

const db = createDb("./app.db", {
  allowExtensions: true, // required: loads the sqlite-vec extension
  plugins: [vector({ docs: { field: "embedding", dimensions: 384 } })],
});

await db.collection("docs").create({
  data: { title: "Black holes", embedding: await embed("Black holes …") },
});

const hits = await db.collection("docs").findSimilar({
  vector: await embed("astrophysics"),
  topK: 5,
  where: { published: true }, // optional structured filter
});
// [ { _id, title, _distance, … } ]  — nearest first

You bring the embeddings (from any model — OpenAI, local, etc.); monlite stores and searches them.

Install

npm install @monlite/core @monlite/vector

@monlite/vector depends on sqlite-vec, which ships prebuilt native binaries. It works on both monlite backends (better-sqlite3 and node:sqlite), but the database must be opened with { allowExtensions: true }.

API

Plugin

vector(spec: Record<string, {
  field: string;               // document field holding the embedding (number[])
  dimensions: number;          // must match your embedding model's output size
  distance?: "l2" | "cosine"; // default "l2"
}>): MonlitePlugin

findSimilar

collection.findSimilar({
  vector: number[],         // query embedding (length must equal dimensions)
  topK?: number,            // number of results (default 10)
  where?: WhereInput<T>,    // combine with a normal monlite filter
}): Promise<Array<WithId<T> & { _distance: number }>>

Results are ordered nearest-first; _distance is the raw metric (smaller = closer). Documents without a valid embedding field are not indexed.

Reindex

import { reindex } from "@monlite/vector";
reindex(db, "docs", { field: "embedding", dimensions: 384 });

Dynamic store — createVectorStore(db)

The vector() plugin attaches semantic search to a collection with a static spec. For a programmatic store over collections created at runtime — RAG corpora, per-tenant indexes, "give me a vector table for this id" — use createVectorStore(db):

import { createDb } from "@monlite/core";
import { createVectorStore } from "@monlite/vector";

const db = createDb("./rag.db", { allowExtensions: true });
const store = createVectorStore(db);

store.ensureCollection("docs", { dimensions: 384, indexedFields: ["docId"] });
store.upsert("docs", [{ id: "c1", vector: emb, metadata: { docId: "d1", text } }]);

// where on an indexed field is applied inside the KNN — exact pre-filtered recall
store.search("docs", { vector: q, topK: 5, where: { docId: "d1" } });
store.delete("docs", { where: { docId: "d1" } });

Synchronous (raw SQLite). Each collection maps to its own vec0 table; indexedFields become filterable metadata columns, and the rest of metadata rides in a +payload column. Scales well to ~1M vectors locally; beyond that use a dedicated vector database.

How it works

For each configured collection, the plugin creates a sqlite-vec vec0 virtual table keyed by the document _id, backfills existing documents on init, and keeps the index current via the plugin afterWrite hook. findSimilar runs a KNN query and returns the live documents in distance order.

Multi-process ingest

afterWrite only sees writes from its own connection. If a separate process ingests vectors (the common agent pattern), call collection.catchUp() in the searching process to incrementally index new vectors and reconcile cross-process deletes before querying — no full reindex needed:

db.collection("memories").catchUp(); // → { indexed, removed }; call periodically
await db.collection("memories").findSimilar({ vector, topK: 5 });

Hybrid search

Combine keyword (FTS) and semantic (vector) results for the best retrieval quality. hybridSearch runs both and fuses the rankings with Reciprocal Rank Fusion — no score normalization needed.

import { createDb } from "@monlite/core";
import { fts } from "@monlite/fts";
import { vector, hybridSearch } from "@monlite/vector";

const db = createDb("./app.db", {
  allowExtensions: true,
  plugins: [
    fts({ docs: ["title", "body"] }),
    vector({ docs: { field: "embedding", dimensions: 384 } }),
  ],
});

const hits = await hybridSearch(db.collection("docs"), {
  text: "black holes",              // keyword arm (FTS)
  vector: await embed("black holes"), // semantic arm (vector)
  topK: 10,
  where: { published: true },       // applied to both arms
});
// [ { _id, title, …, _rrf } ]  — fused, best first

If @monlite/fts is not configured on the collection, it falls back to vector-only.

License

MIT