{"id":51246877,"url":"https://github.com/qataruts/monlite","last_synced_at":"2026-06-30T06:00:42.391Z","repository":{"id":367639499,"uuid":"1281445089","full_name":"qataruts/monlite","owner":"qataruts","description":"Documents, vectors, cache, queue, and cron in one SQLite file. The local backend for AI agents.","archived":false,"fork":false,"pushed_at":"2026-06-29T04:08:50.000Z","size":729,"stargazers_count":26,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-29T05:25:31.244Z","etag":null,"topics":["ai-agents","document-database","embedded-database","full-text-search","job-queue","local-first","rag","sqlite","typescript","vector-search"],"latest_commit_sha":null,"homepage":"https://qataruts.github.io/monlite/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qataruts.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-26T15:04:14.000Z","updated_at":"2026-06-29T05:09:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/qataruts/monlite","commit_stats":null,"previous_names":["qataruts/monlite"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/qataruts/monlite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qataruts%2Fmonlite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qataruts%2Fmonlite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qataruts%2Fmonlite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qataruts%2Fmonlite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qataruts","download_url":"https://codeload.github.com/qataruts/monlite/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qataruts%2Fmonlite/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34954283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","document-database","embedded-database","full-text-search","job-queue","local-first","rag","sqlite","typescript","vector-search"],"created_at":"2026-06-29T05:00:30.333Z","updated_at":"2026-06-30T06:00:42.385Z","avatar_url":"https://github.com/qataruts.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# monlite\n\n\u003e **The local-first backend in a file.** Documents, full-text + vector search, cache, queue, and\n\u003e cron — one SQLite file, a zero-dependency TypeScript core, and the *same* API on Postgres when\n\u003e you scale.\n\n```ts\nimport { createDb } from \"@monlite/core\";\n\nconst db = createDb(\"./app.db\");\nconst users = db.collection(\"users\");\nawait users.create({ data: { name: \"Ada\", age: 30, tags: [\"admin\"] } });\nawait users.findMany({ where: { age: { gte: 18 }, tags: { has: \"admin\" } } });\n```\n\nNo server. No migrations. No configuration. No native build (Node 22.5+ uses the built-in\n`node:sqlite`). Backup is `cp app.db backup.db`.\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\n---\n\n## One file replaces the whole local stack\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` file — install only what you use, the core stays zero-dependency:\n\n| Instead of | Use | Gives you |\n|---|---|---|\n| MongoDB / Mongoose | [`@monlite/core`](https://www.npmjs.com/package/@monlite/core) | document collections, a typed query language, transactions, reactive `watch()` |\n| Elasticsearch / Typesense | [`@monlite/fts`](https://www.npmjs.com/package/@monlite/fts) | full-text search — `collection.search()` |\n| Qdrant / Pinecone | [`@monlite/vector`](https://www.npmjs.com/package/@monlite/vector) | vector / semantic search, `findSimilar()`, hybrid RAG |\n| Redis (cache) | [`@monlite/kv`](https://www.npmjs.com/package/@monlite/kv) | cache, atomic locks, TTLs, pub/sub, sorted sets |\n| BullMQ + Redis | [`@monlite/queue`](https://www.npmjs.com/package/@monlite/queue) | durable job queue — retries, backoff, dedupe, concurrency |\n| A cron server | [`@monlite/cron`](https://www.npmjs.com/package/@monlite/cron) | persisted scheduled jobs (time zones, jitter) |\n| Firebase / Pusher | [`@monlite/realtime`](https://www.npmjs.com/package/@monlite/realtime) | stream live queries \u0026 docs to clients over SSE |\n| MongoDB Atlas sync | [`@monlite/sync`](https://www.npmjs.com/package/@monlite/sync) | local-first replication to MongoDB / PostgreSQL / MySQL |\n| A managed Postgres | [`@monlite/postgres`](https://www.npmjs.com/package/@monlite/postgres) | **the same API on a networked Postgres** when you outgrow one file |\n\nNo Docker. No `.env` full of connection strings. One file, one API, `node serve.mjs`.\n\n---\n\n## Install\n\n**Batteries-included** — the whole stack in one package:\n\n```bash\nnpm install monlite\n```\n\n```ts\nimport { createDb, kv, createQueue, createCron, fts, vector } from \"monlite\";\n```\n\nOr the **minimal, zero-dependency core**, plus packages à la carte:\n\n```bash\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\n---\n\n## A real query language — typed, not a toy\n\nA Mongo/Prisma-style API. Typed collections get compile-time-checked `where`/`orderBy`, and return\ntypes that narrow with `select`.\n\n```ts\ninterface Order {\n  customerId: string;\n  items: { sku: string; qty: number }[];\n  status: \"pending\" | \"shipped\" | \"returned\";\n  total: number;\n}\nconst orders = db.collection\u003cOrder\u003e(\"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) =\u003e {\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`/`createMany`, `findMany`/`findFirst`/`findById`, `update`/`updateMany`,\n`upsert`, `delete`/`deleteMany`, `count`/`exists`/`distinct`, `aggregate`/`groupBy`, `bulkWrite`,\n`findOneAndUpdate`, TTL collections, `explain()`, and structured (columnar) collections.\n\n---\n\n## Real-time reactivity — a local Firebase\n\n`collection.watch()` returns a live result set that re-emits only when a *relevant* change lands\n(row-level matching — no spurious re-renders), with `added`/`removed`/`changed`/`moved` deltas.\n\n```ts\n// initial snapshot, then re-fires only when an admin is added/changed/removed\nusers.watch({ where: { roles: { has: \"admin\" } } }, ({ results, added, removed }) =\u003e\n  renderAdminList(results),\n);\n\n// single-document listener (Firebase-style onSnapshot) — doc is null on delete\norders.watchDoc(\"o-123\", (doc) =\u003e render(doc));\n```\n\nEnable the **change feed** (`{ changefeed: true }`) for a durable, resumable, ordered stream — and\n`watch()` then also sees writes from **other processes** on the same file:\n\n```ts\nfor await (const ev of db.changes(\"orders\", { since: lastSeq })) {\n  // { seq, collection, id, op: \"upsert\" | \"delete\", ts } — resumable by seq\n}\n```\n\n---\n\n## Search — full-text, vector, and hybrid\n\nAdd the plugins, point them at fields, and they index automatically on every write. Keyword\nranking and vector similarity fuse into one ranked list via Reciprocal Rank Fusion.\n\n```ts\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---\n\n## Cache, queue, and cron — the operational trio\n\n```ts\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) =\u003e 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 * * *\", () =\u003e queue.add(\"cleanup\", {}));\n```\n\nThis is the **AI-agent backend** in one file — document memory, semantic recall, exactly-once job\nclaims, locks, a task queue, and scheduling, with no Docker and no connection strings.\n\n---\n\n## Outgrow one file? The same code runs on Postgres\n\nThe collection API is engine-agnostic. Develop against a local `.db`; when you need a networked,\nmulti-writer backend, **swap the engine, not your app**:\n\n```ts\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 **entire** surface\non Postgres (documents as JSONB): all CRUD, the full query language, `aggregate`/`groupBy`,\n`explain()`, realtime `watch()` over `LISTEN/NOTIFY` (truly cross-process), full-text search\n(`tsvector`), vector search (pgvector), the job queue (`SKIP LOCKED`), cache, and cron — the *same*\nplugins and the same calls. A ready-to-run [`monlite/postgres`](https://hub.docker.com/r/monlite/postgres)\nDocker image bundles Postgres 16 + pgvector, preconfigured.\n\n---\n\n## Runs everywhere SQLite runs\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 `.db` file**, pure stdlib |\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---\n\n## Why monlite\n\n- **vs. raw SQLite** — you'd hand-write the document layer, query translator, FTS/vector wiring,\n  change feed, sync engine, and all the types. monlite is that work, done and tested.\n- **vs. MongoDB + Redis + Qdrant** — for local / edge / desktop / single-machine work you'd run\n  three services to solve one problem. monlite is one file, one API, zero infrastructure — and\n  scales to Postgres with the same code when you genuinely need a server.\n- **vs. Firebase / Supabase** — great for shared cloud state, awkward when you need to work offline,\n  ship a CLI, or keep data on-device. monlite is local-first; `@monlite/sync` adds the cloud when\n  you want it.\n\n---\n\n## Documentation\n\nFull guide at **[qataruts.github.io/monlite](https://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)\n- **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)\n- **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)\n- **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/`](examples/). The [live demo](https://qataruts.github.io/monlite/demo)\nruns every package — documents, FTS5, vector search, cache, queue, cron — 100% in the browser on\nSQLite-WASM, with embeddings computed on-device via Transformers.js.\n\n## Status\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\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqataruts%2Fmonlite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqataruts%2Fmonlite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqataruts%2Fmonlite/lists"}