cd /news/ai-agents/monlite-the-complete-back-end-for-ai… · home topics ai-agents article
[ARTICLE · art-46751] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Monlite: The complete back end for AI agents – in one file

Monlite launches a zero-dependency TypeScript backend for AI agents that combines memory, vector search, task queues, locks, and cron into a single SQLite file, eliminating the need for Docker or multiple services. The open-source tool scales to Postgres when needed and is available on npm.

read8 min views1 publishedJul 1, 2026
Monlite: The complete back end for AI agents – in one file
Image: source

Document

memory, semantic (vector) recall, full-text search, a durabletask queue, atomiclocks, cache, andcron— over a single SQLite file, with a zero-dependency TypeScript core.No Docker. No connection strings. Nothing to run.And thesame codescales to Postgres the day you need it.

A coding agent, RAG pipeline, or autonomous worker needs memory, semantic search, a job queue, and locks. That's normally MongoDB + Qdrant + Redis + BullMQ — four services and a Docker compose file. monlite is all of it, in a file you can cp to back up:

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

// one file = the agent's entire backend
const db = createDb("./agent.db", {
  allowExtensions: true,
  plugins: [vector({ memory: { field: "embedding", dimensions: 384 } })],
});

// 🧠 memory — typed document collections
await db.collection("memory").create({ data: { note: "user prefers dark mode", embedding } });

// 🔎 semantic recall — vector search over embeddings
const recall = await db.collection("memory").findSimilar({ vector: query, topK: 5 });

// 🔒 an atomic lock (run-once)  +  📋 a durable task queue (retries, backoff, dedupe, concurrency)
if (kv(db).setNX("lock:ingest", 1, { ttl: 30_000 })) startIngest();
createQueue(db).process("embed", (job) => embed(job.payload.text), { concurrency: 4 });

Exactly-once job claims, locks, scheduling, and full-text + semantic search — with no server, no migrations, and no native build (Node 22.5+ uses the built-in node:sqlite

).

📖 Docs · 🎮 Live demo (runs in your browser) · 📦 npm · 💻 GitHub

Most apps, CLIs, and AI agents wire up the same services. monlite gives you each one as a small package over a single .db

file — install only what you use, the core stays zero-dependency:

Instead of Use Gives you
MongoDB / Mongoose
@monlite/core

watch()

@monlite/fts

collection.search()

@monlite/vector

findSimilar()

, hybrid RAG@monlite/kv

@monlite/queue

@monlite/cron

@monlite/realtime

@monlite/sync

@monlite/postgres

the same API on a networked Postgres when you outgrow one fileNo Docker. No .env

full of connection strings. One file, one API, node serve.mjs

.

Batteries-included — the whole stack in one package:

npm install monlite
js
import { createDb, kv, createQueue, createCron, fts, vector } from "monlite";

Or the minimal, zero-dependency core, plus packages à la carte:

npm install @monlite/core                 # zero-dep core (Node ≥ 22.5, built-in node:sqlite)
npm install @monlite/core better-sqlite3  # Node 18/20, or to skip the experimental flag

npm install @monlite/fts        # full-text search          @monlite/vector   # semantic search
npm install @monlite/kv         # cache, locks, pub/sub      @monlite/queue    # durable job queue
npm install @monlite/cron       # scheduler                  @monlite/realtime # live queries over SSE
npm install @monlite/postgres   # run the same API on Postgres
npm install @monlite/sync       # cloud sync (MongoDB / PostgreSQL / MySQL)
npm install @monlite/wasm       # browser / SQLite-WASM      @monlite/electron # Electron main↔renderer

Zero-install inspector: ** npx @monlite/studio app.db** opens a local web UI to browse collections, view documents, and run queries.

A Mongo/Prisma-style API. Typed collections get compile-time-checked where

/orderBy

, and return types that narrow with select

.

interface Order {
  customerId: string;
  items: { sku: string; qty: number }[];
  status: "pending" | "shipped" | "returned";
  total: number;
}
const orders = db.collection<Order>("orders");

// query inside arrays of objects
await orders.findMany({ where: { items: { elemMatch: { sku: "WIDGET", qty: { gte: 5 } } } } });

// case-insensitive regex
await orders.findMany({ where: { status: { regex: "^pend", mode: "insensitive" } } });

// grouped aggregation — GROUP BY with sums, HAVING, top-N
await orders.groupBy({
  by: ["customerId"],
  where: { status: "shipped" },
  _sum: { total: true },
  orderBy: { _sum: { total: "desc" } },
  take: 10,
});

// atomic transactions — await inside, all-or-nothing
await db.transactionAsync(async (tx) => {
  const accounts = tx.collection("accounts");
  await accounts.update({ where: { _id: "acc-1" }, data: { $inc: { balance: -100 } } });
  await accounts.update({ where: { _id: "acc-2" }, data: { $inc: { balance: +100 } } });
});

// cross-process compare-and-swap — exactly-once job claim
const claimed = await orders.findOneAndUpdate({
  where: { status: "pending" },
  data: { $set: { status: "active" } },
  returnDocument: "after",
}); // N workers race; exactly one wins, the rest get null

Full surface: create

/createMany

, findMany

/findFirst

/findById

, update

/updateMany

, upsert

, delete

/deleteMany

, count

/exists

/distinct

, aggregate

/groupBy

, bulkWrite

, findOneAndUpdate

, TTL collections, explain()

, and structured (columnar) collections.

collection.watch()

returns a live result set that re-emits only when a relevant change lands (row-level matching — no spurious re-renders), with added

/removed

/changed

/moved

deltas.

// initial snapshot, then re-fires only when an admin is added/changed/removed
users.watch({ where: { roles: { has: "admin" } } }, ({ results, added, removed }) =>
  renderAdminList(results),
);

// single-document listener (Firebase-style onSnapshot) — doc is null on delete
orders.watchDoc("o-123", (doc) => render(doc));

Enable the change feed ({ changefeed: true }

) for a durable, resumable, ordered stream — and watch()

then also sees writes from other processes on the same file:

for await (const ev of db.changes("orders", { since: lastSeq })) {
  // { seq, collection, id, op: "upsert" | "delete", ts } — resumable by seq
}

Add the plugins, point them at fields, and they index automatically on every write. Keyword ranking and vector similarity fuse into one ranked list via Reciprocal Rank Fusion.

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 } }),
  ],
});

await db.collection("docs").search("brown fox");                 // keyword (FTS5)
await db.collection("docs").findSimilar({ vector: emb, topK: 5 }); // semantic (sqlite-vec)

const hits = await hybridSearch(db.collection("docs"), {          // both, fused
  text: "machine learning", vector: await embed("machine learning"),
  topK: 10, where: { published: true },
});

Indexing is linear at scale — verified ingesting 100K documents in ~0.8s and 50K vectors in ~8s (no O(n²) re-index), comfortably backing a 10K–100K-document RAG corpus.

import { kv } from "@monlite/kv";
import { createQueue } from "@monlite/queue";
import { createCron } from "@monlite/cron";

// Redis-like cache: get/set with TTL, atomic locks, counters, sorted sets, pub/sub
const cache = kv(db);
cache.set("session:42", { user: "ali" }, { ttl: 60_000 });
if (cache.setNX("lock:job:42", 1, { ttl: 30_000 })) runOnce(); // atomic lock

// durable job queue: retries, backoff, dedupe, concurrency, rate limits
const queue = createQueue(db, { maxAttempts: 3 });
queue.process("embed", async (job) => embed(job.payload.text), { concurrency: 4 });

// persisted scheduler: 5-field cron, time zones, jitter, multi-process safe
const cron = createCron(db);
cron.schedule("nightly", "0 3 * * *", () => queue.add("cleanup", {}));

The full AI-agent-backend walkthrough puts these together with memory + semantic recall into one runtime.

The collection API is engine-agnostic. Develop against a local .db

; when you need a networked, multi-writer backend, swap the engine, not your app:

import { createDb } from "@monlite/core";        const db = createDb("app.db");      // local
import { createDb } from "@monlite/postgres";    const db = createDb("postgres://…"); // server

@monlite/postgres runs the

entire surface on Postgres (documents as JSONB): all CRUD, the full query language,

aggregate

/groupBy

, explain()

, realtime watch()

over LISTEN/NOTIFY

(truly cross-process), full-text search (tsvector

), vector search (pgvector), the job queue (SKIP LOCKED

), cache, and cron — the sameplugins and the same calls. A ready-to-run

Docker image bundles Postgres 16 + pgvector, preconfigured.

monlite/postgres

Environment How
Node 22.5+ @monlite/core — built-in node:sqlite , zero native build
Node 18/20 @monlite/core + better-sqlite3 (auto-selected when present)
Browser @monlite/wasm — same API on SQLite-WASM
Electron @monlite/electron — DB in main, same API in renderers over IPC
Python pip install monlite — the same , pure stdlib.db file

The Python port is at feature parity — documents (transactions, aggregation, change feed), kv, queue, cron, FTS5, and vector search — reading and writing the same file as the Node packages, with a cross-runtime interop suite round-tripping a database between them. So Python ingests/embeds while Node serves, over one file.

from monlite import create_db, kv
db = create_db("app.db")                       # the same file your Node process uses
db.collection("users").find_many(where={"tags": {"has": "admin"}})
kv(db).set("session:42", {"user": "ali"}, ttl=60_000)

vs. raw SQLite— you'd hand-write the document layer, query translator, FTS/vector wiring, change feed, sync engine, and all the types. monlite is that work, done and tested.vs. MongoDB + Redis + Qdrant— for local / edge / desktop / single-machine work you'd run three services to solve one problem. monlite is one file, one API, zero infrastructure — and scales to Postgres with the same code when you genuinely need a server.vs. Firebase / Supabase— great for shared cloud state, awkward when you need to work offline, ship a CLI, or keep data on-device. monlite is local-first;@monlite/sync

adds the cloud when you want it.

Full guide at ** qataruts.github.io/monlite**:

Getting started·** Core**—documents·queries·aggregation·realtime·transactionsPackagespostgres·fts·vector·kv·queue·cron·syncGuidesAI-agent backend·production·migrationsReferencefile format·Python·benchmarks

Runnable demos in examples/. The

live demoruns every package — documents, FTS5, vector search, cache, queue, cron — 100% in the browser on SQLite-WASM, with embeddings computed on-device via Transformers.js.

Production-ready and published; the 2.x core API is frozen. The Postgres engine ( @monlite/postgres) runs the entire surface — documents, queries, aggregation, realtime, full-text, vector, queue, kv, and cron — verified against live Postgres. See each package on npm for its current version and changelog.

MIT

── more in #ai-agents 4 stories · sorted by recency
── more on @monlite 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/monlite-the-complete…] indexed:0 read:8min 2026-07-01 ·