{"slug": "monlite-the-complete-back-end-for-ai-agents-in-one-file", "title": "Monlite: The complete back end for AI agents – in one file", "summary": "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.", "body_md": "Document\n\nmemory, 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.\n\nA coding agent, RAG pipeline, or autonomous worker needs memory, semantic search, a job queue, and\nlocks. That's normally MongoDB + Qdrant + Redis + BullMQ — four services and a Docker compose file.\n**monlite is all of it, in a file you can cp to back up:**\n\n``` js\nimport { createDb } from \"@monlite/core\";\nimport { vector } from \"@monlite/vector\";\nimport { createQueue } from \"@monlite/queue\";\nimport { kv } from \"@monlite/kv\";\n\n// one file = the agent's entire backend\nconst db = createDb(\"./agent.db\", {\n  allowExtensions: true,\n  plugins: [vector({ memory: { field: \"embedding\", dimensions: 384 } })],\n});\n\n// 🧠 memory — typed document collections\nawait db.collection(\"memory\").create({ data: { note: \"user prefers dark mode\", embedding } });\n\n// 🔎 semantic recall — vector search over embeddings\nconst recall = await db.collection(\"memory\").findSimilar({ vector: query, topK: 5 });\n\n// 🔒 an atomic lock (run-once)  +  📋 a durable task queue (retries, backoff, dedupe, concurrency)\nif (kv(db).setNX(\"lock:ingest\", 1, { ttl: 30_000 })) startIngest();\ncreateQueue(db).process(\"embed\", (job) => embed(job.payload.text), { concurrency: 4 });\n```\n\nExactly-once job claims, locks, scheduling, and full-text + semantic search — with **no server, no\nmigrations, and no native build** (Node 22.5+ uses the built-in `node:sqlite`\n\n).\n\n📖 [Docs](https://qataruts.github.io/monlite) · 🎮 [Live demo](https://qataruts.github.io/monlite/demo) (runs in your browser) · 📦 [npm](https://www.npmjs.com/package/monlite) · 💻 [GitHub](https://github.com/qataruts/monlite)\n\nMost apps, CLIs, and AI agents wire up the same services. monlite gives you each one as a small\npackage over a single `.db`\n\nfile — install only what you use, the core stays zero-dependency:\n\n| Instead of | Use | Gives you |\n|---|---|---|\n| MongoDB / Mongoose |\n`@monlite/core` |\n\n`watch()`\n\n`@monlite/fts`\n\n`collection.search()`\n\n`@monlite/vector`\n\n`findSimilar()`\n\n, hybrid RAG`@monlite/kv`\n\n`@monlite/queue`\n\n`@monlite/cron`\n\n`@monlite/realtime`\n\n`@monlite/sync`\n\n`@monlite/postgres`\n\n**the same API on a networked Postgres** when you outgrow one fileNo Docker. No `.env`\n\nfull of connection strings. One file, one API, `node serve.mjs`\n\n.\n\n**Batteries-included** — the whole stack in one package:\n\n```\nnpm install monlite\njs\nimport { createDb, kv, createQueue, createCron, fts, vector } from \"monlite\";\n```\n\nOr the **minimal, zero-dependency core**, plus packages à la carte:\n\n```\nnpm install @monlite/core                 # zero-dep core (Node ≥ 22.5, built-in node:sqlite)\nnpm install @monlite/core better-sqlite3  # Node 18/20, or to skip the experimental flag\n\nnpm install @monlite/fts        # full-text search          @monlite/vector   # semantic search\nnpm install @monlite/kv         # cache, locks, pub/sub      @monlite/queue    # durable job queue\nnpm install @monlite/cron       # scheduler                  @monlite/realtime # live queries over SSE\nnpm install @monlite/postgres   # run the same API on Postgres\nnpm install @monlite/sync       # cloud sync (MongoDB / PostgreSQL / MySQL)\nnpm install @monlite/wasm       # browser / SQLite-WASM      @monlite/electron # Electron main↔renderer\n```\n\nZero-install inspector: ** npx @monlite/studio app.db** opens a local web UI to browse\ncollections, view documents, and run queries.\n\nA Mongo/Prisma-style API. Typed collections get compile-time-checked `where`\n\n/`orderBy`\n\n, and return\ntypes that narrow with `select`\n\n.\n\n```\ninterface Order {\n  customerId: string;\n  items: { sku: string; qty: number }[];\n  status: \"pending\" | \"shipped\" | \"returned\";\n  total: number;\n}\nconst orders = db.collection<Order>(\"orders\");\n\n// query inside arrays of objects\nawait orders.findMany({ where: { items: { elemMatch: { sku: \"WIDGET\", qty: { gte: 5 } } } } });\n\n// case-insensitive regex\nawait orders.findMany({ where: { status: { regex: \"^pend\", mode: \"insensitive\" } } });\n\n// grouped aggregation — GROUP BY with sums, HAVING, top-N\nawait orders.groupBy({\n  by: [\"customerId\"],\n  where: { status: \"shipped\" },\n  _sum: { total: true },\n  orderBy: { _sum: { total: \"desc\" } },\n  take: 10,\n});\n\n// atomic transactions — await inside, all-or-nothing\nawait db.transactionAsync(async (tx) => {\n  const accounts = tx.collection(\"accounts\");\n  await accounts.update({ where: { _id: \"acc-1\" }, data: { $inc: { balance: -100 } } });\n  await accounts.update({ where: { _id: \"acc-2\" }, data: { $inc: { balance: +100 } } });\n});\n\n// cross-process compare-and-swap — exactly-once job claim\nconst claimed = await orders.findOneAndUpdate({\n  where: { status: \"pending\" },\n  data: { $set: { status: \"active\" } },\n  returnDocument: \"after\",\n}); // N workers race; exactly one wins, the rest get null\n```\n\nFull surface: `create`\n\n/`createMany`\n\n, `findMany`\n\n/`findFirst`\n\n/`findById`\n\n, `update`\n\n/`updateMany`\n\n,\n`upsert`\n\n, `delete`\n\n/`deleteMany`\n\n, `count`\n\n/`exists`\n\n/`distinct`\n\n, `aggregate`\n\n/`groupBy`\n\n, `bulkWrite`\n\n,\n`findOneAndUpdate`\n\n, TTL collections, `explain()`\n\n, and structured (columnar) collections.\n\n`collection.watch()`\n\nreturns a live result set that re-emits only when a *relevant* change lands\n(row-level matching — no spurious re-renders), with `added`\n\n/`removed`\n\n/`changed`\n\n/`moved`\n\ndeltas.\n\n```\n// initial snapshot, then re-fires only when an admin is added/changed/removed\nusers.watch({ where: { roles: { has: \"admin\" } } }, ({ results, added, removed }) =>\n  renderAdminList(results),\n);\n\n// single-document listener (Firebase-style onSnapshot) — doc is null on delete\norders.watchDoc(\"o-123\", (doc) => render(doc));\n```\n\nEnable the **change feed** (`{ changefeed: true }`\n\n) for a durable, resumable, ordered stream — and\n`watch()`\n\nthen also sees writes from **other processes** on the same file:\n\n``` js\nfor await (const ev of db.changes(\"orders\", { since: lastSeq })) {\n  // { seq, collection, id, op: \"upsert\" | \"delete\", ts } — resumable by seq\n}\n```\n\nAdd 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.\n\n``` js\nimport { fts } from \"@monlite/fts\";\nimport { vector, hybridSearch } from \"@monlite/vector\";\n\nconst db = createDb(\"./app.db\", {\n  allowExtensions: true,\n  plugins: [\n    fts({ docs: [\"title\", \"body\"] }),\n    vector({ docs: { field: \"embedding\", dimensions: 384 } }),\n  ],\n});\n\nawait db.collection(\"docs\").search(\"brown fox\");                 // keyword (FTS5)\nawait db.collection(\"docs\").findSimilar({ vector: emb, topK: 5 }); // semantic (sqlite-vec)\n\nconst hits = await hybridSearch(db.collection(\"docs\"), {          // both, fused\n  text: \"machine learning\", vector: await embed(\"machine learning\"),\n  topK: 10, where: { published: true },\n});\n```\n\nIndexing is **linear at scale** — verified ingesting 100K documents in ~0.8s and 50K vectors in\n~8s (no O(n²) re-index), comfortably backing a 10K–100K-document RAG corpus.\n\n``` js\nimport { kv } from \"@monlite/kv\";\nimport { createQueue } from \"@monlite/queue\";\nimport { createCron } from \"@monlite/cron\";\n\n// Redis-like cache: get/set with TTL, atomic locks, counters, sorted sets, pub/sub\nconst cache = kv(db);\ncache.set(\"session:42\", { user: \"ali\" }, { ttl: 60_000 });\nif (cache.setNX(\"lock:job:42\", 1, { ttl: 30_000 })) runOnce(); // atomic lock\n\n// durable job queue: retries, backoff, dedupe, concurrency, rate limits\nconst queue = createQueue(db, { maxAttempts: 3 });\nqueue.process(\"embed\", async (job) => embed(job.payload.text), { concurrency: 4 });\n\n// persisted scheduler: 5-field cron, time zones, jitter, multi-process safe\nconst cron = createCron(db);\ncron.schedule(\"nightly\", \"0 3 * * *\", () => queue.add(\"cleanup\", {}));\n```\n\nThe full [AI-agent-backend walkthrough](https://qataruts.github.io/monlite/guides/ai-agent-backend)\nputs these together with memory + semantic recall into one runtime.\n\nThe collection API is engine-agnostic. Develop against a local `.db`\n\n; when you need a networked,\nmulti-writer backend, **swap the engine, not your app**:\n\n``` js\nimport { createDb } from \"@monlite/core\";        const db = createDb(\"app.db\");      // local\nimport { createDb } from \"@monlite/postgres\";    const db = createDb(\"postgres://…\"); // server\n```\n\n[ @monlite/postgres](https://www.npmjs.com/package/@monlite/postgres) runs the\n\n**entire** surface on Postgres (documents as JSONB): all CRUD, the full query language,\n\n`aggregate`\n\n/`groupBy`\n\n,\n`explain()`\n\n, realtime `watch()`\n\nover `LISTEN/NOTIFY`\n\n(truly cross-process), full-text search\n(`tsvector`\n\n), vector search (pgvector), the job queue (`SKIP LOCKED`\n\n), cache, and cron — the *same*plugins and the same calls. A ready-to-run\n\n[Docker image bundles Postgres 16 + pgvector, preconfigured.](https://hub.docker.com/r/monlite/postgres)\n\n`monlite/postgres`\n\n| Environment | How |\n|---|---|\n| Node 22.5+ | `@monlite/core` — built-in `node:sqlite` , zero native build |\n| Node 18/20 | `@monlite/core` + `better-sqlite3` (auto-selected when present) |\n| Browser | `@monlite/wasm` — same API on SQLite-WASM |\n| Electron | `@monlite/electron` — DB in main, same API in renderers over IPC |\n| Python | `pip install monlite` — the same , pure stdlib`.db` file |\n\nThe **Python port** is at feature parity — documents (transactions, aggregation, change feed), kv,\nqueue, cron, FTS5, and vector search — reading and writing the same file as the Node packages, with\na cross-runtime interop suite round-tripping a database between them. So **Python ingests/embeds\nwhile Node serves**, over one file.\n\n``` python\nfrom monlite import create_db, kv\ndb = create_db(\"app.db\")                       # the same file your Node process uses\ndb.collection(\"users\").find_many(where={\"tags\": {\"has\": \"admin\"}})\nkv(db).set(\"session:42\", {\"user\": \"ali\"}, ttl=60_000)\n```\n\n**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`\n\nadds the cloud when you want it.\n\nFull guide at ** qataruts.github.io/monlite**:\n\n**Getting started**·** Core**—[documents](https://qataruts.github.io/monlite/core/documents)·[queries](https://qataruts.github.io/monlite/core/queries)·[aggregation](https://qataruts.github.io/monlite/core/aggregation)·[realtime](https://qataruts.github.io/monlite/core/realtime)·[transactions](https://qataruts.github.io/monlite/core/transactions)**Packages**—[postgres](https://qataruts.github.io/monlite/packages/postgres)·[fts](https://qataruts.github.io/monlite/packages/fts)·[vector](https://qataruts.github.io/monlite/packages/vector)·[kv](https://qataruts.github.io/monlite/packages/kv)·[queue](https://qataruts.github.io/monlite/packages/queue)·[cron](https://qataruts.github.io/monlite/packages/cron)·[sync](https://qataruts.github.io/monlite/packages/sync)**Guides**—[AI-agent backend](https://qataruts.github.io/monlite/guides/ai-agent-backend)·[production](https://qataruts.github.io/monlite/guides/production)·[migrations](https://qataruts.github.io/monlite/guides/migrations)**Reference**—[file format](https://qataruts.github.io/monlite/reference/file-format)·[Python](https://qataruts.github.io/monlite/reference/python)·[benchmarks](https://qataruts.github.io/monlite/reference/benchmarks)\n\nRunnable demos in [ examples/](/qataruts/monlite/blob/main/examples). The\n\n[live demo](https://qataruts.github.io/monlite/demo)runs every package — documents, FTS5, vector search, cache, queue, cron — 100% in the browser on SQLite-WASM, with embeddings computed on-device via Transformers.js.\n\nProduction-ready and published; the 2.x core API is frozen. The **Postgres engine**\n([ @monlite/postgres](https://www.npmjs.com/package/@monlite/postgres)) runs the entire surface —\ndocuments, queries, aggregation, realtime, full-text, vector, queue, kv, and cron — verified\nagainst live Postgres. See each package on npm for its current version and changelog.\n\nMIT", "url": "https://wpnews.pro/news/monlite-the-complete-back-end-for-ai-agents-in-one-file", "canonical_source": "https://github.com/qataruts/monlite", "published_at": "2026-07-01 14:11:31+00:00", "updated_at": "2026-07-01 14:20:41.410311+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-infrastructure"], "entities": ["Monlite", "SQLite", "Postgres", "Node.js", "npm", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/monlite-the-complete-back-end-for-ai-agents-in-one-file", "markdown": "https://wpnews.pro/news/monlite-the-complete-back-end-for-ai-agents-in-one-file.md", "text": "https://wpnews.pro/news/monlite-the-complete-back-end-for-ai-agents-in-one-file.txt", "jsonld": "https://wpnews.pro/news/monlite-the-complete-back-end-for-ai-agents-in-one-file.jsonld"}}