monlite (Python)
The local-first database for Python — documents, cache, durable queue, cron, and full-text search over one SQLite file, with a pure-standard-library core. No dependencies required.
monlite is the Python port of monlite. It reads and writes the same
.db file as the TypeScript @monlite/* packages — same documents, change feed, _kv/sorted-set
tables, _jobs queue, _schedules, and FTS5 index — so Python ingests or embeds while Node
serves (or any split you like). Every table layout is byte-compatible and covered by an interop
suite that round-trips a file between the two runtimes.
pip install monlite
Quick start
from monlite import create_db, kv
db = create_db("app.db")
users = db.collection("users")
users.create({"name": "Ali", "age": 30, "tags": ["admin"]})
users.create_many([{"name": "Sara", "age": 25}, {"name": "Omar", "age": 40}])
adults = users.find_many(where={"age": {"gte": 18}}, order_by={"age": "asc"})
ali = users.find_first(where={"name": "Ali"})
users.update({"_id": ali["_id"]}, {"$inc": {"age": 1}, "$push": {"tags": "vip"}})
count = users.count(where={"role": "admin"})
cache = kv(db)
cache.set("session:42", {"user": "ali"}, ttl=60_000)
Query operators
Mongo/Prisma-style, mirroring the TypeScript API (snake_case method names):
where={"age": {"gte": 18, "lt": 65}}
where={"role": {"in": ["admin", "editor"]}, "name": {"not": "root"}}
where={"name": {"contains": "ali", "mode": "insensitive"}}
where={"sku": {"startsWith": "AB", "endsWith": "-1"}}
where={"email": {"regex": r"@example\.com$"}}
where={"tags": {"has": "admin"}} # array contains
where={"items": {"elemMatch": {"qty": {"gte": 5}}}} # any array element matches
where={"OR": [{"role": "admin"}, {"age": {"gte": 40}}]}
Update operators: $set, $unset, $inc, $push, $pull, $addToSet. Plus
aggregate(_count=True, _sum=["amt"], _avg=["amt"], _min=[...], _max=[...]) and
group_by("category", _count=True, _sum=["amt"]).
Transactions
with db.transaction(): # nestable via SAVEPOINTs; rolls back on exception
orders.create({...})
inventory.update({"_id": sku}, {"$inc": {"stock": -1}})
Change feed — see what Node wrote (and vice-versa)
Opt in with changefeed=True; writes append to _monlite_changes in the exact format the TS side
reads (upsert/delete ops, the <padded-ms>:<nodeId>:<padded-seq> version string):
db = create_db("shared.db", changefeed=True)
last = 0
while True:
for ch in db.changes(since=last): # ordered; includes Node's writes
handle(ch["coll"], ch["doc_id"], ch["op"])
last = ch["seq"]
time.sleep(0.2)
kv — cache, locks, pub/sub, sorted sets (Redis's local role)
c = kv(db)
c.set("k", {"v": 1}, ttl=60_000); c.incr("hits")
c.set_nx("lock:job", 1, ttl=5_000) # atomic set-if-absent
with c.with_lock("report", ttl_ms=10_000): # ergonomic distributed lock
build_report()
c.subscribe("jobs", lambda m: print("got", m))
c.publish("jobs", {"id": 7}) # same-process now; c.poll() drains other writers
c.zadd("board", 100, "ada"); c.zincrby("board", 5, "bo")
c.zrange("board", 0, -1, rev=True) # leaderboard; zrank/zscore/zrange_by_score too
Durable queue
from monlite import create_queue
q = create_queue(db)
q.add("email", {"to": "a@b.c"}, priority=5, max_attempts=3) # retries + backoff + dedupe (job_id)
q.process("email", lambda payload: send(payload)) # claim+run loop (multi-process safe)
A Node @monlite/queue worker and this one share _jobs — enqueue in Python, process in Node, or
the reverse.
Cron
from monlite import create_cron, next_cron_run
cron = create_cron(db)
cron.schedule("digest", "0 9 * * *", send_digest, tz="Europe/Istanbul", jitter=30_000)
cron.tick() # fire due schedules (call on your own loop; multi-process safe via atomic claim)
next_cron_run("*/15 * * * *") # -> datetime
Full-text search (FTS5)
from monlite import fts
idx = fts(db, "posts", fields=["title", "body"]) # builds the FTS5 index + keeps it current
posts = db.collection("posts")
posts.create({"title": "SQLite is great", "body": "embedded and fast"})
idx.search("sqlite", limit=10) # ranked documents (interop-compatible with Node)
Cross-language interop
Each runtime is a complete, independent library; the shared-file interop is a bonus you opt into. The interop test suite round-trips documents, the change feed, sorted sets, and the queue between Node and Python over one file. See the file format spec for the conventions both sides follow.
Optional extras
The whole stack above is pure standard-library sqlite3. Native extras mirror the TypeScript
packages and install separately:
pip install "monlite[vector]" # semantic search via sqlite-vec
pip install "monlite[postgres]" # sync to PostgreSQL
pip install "monlite[mongo]" # sync to MongoDB
Status
Documents (with transactions, aggregation, and the change feed), kv (cache, locks, pub/sub,
sorted sets), the durable queue, cron, and FTS5 are implemented and covered by tests — including
a cross-runtime interop suite. The [vector] extra and sync adapters are next. The
file format is the contract every part shares.
MIT
Metadata
Release files for monlite 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| monlite-0.2.0.tar.gz | 48.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| monlite-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.3 kB
Release files / monlite-0.2.0.tar.gz
| Download URL | monlite-0.2.0.tar.gz |
|---|---|
| Size | 48.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9248b8c77cc4e41032890484c4bfe8b4070e6e88ef00f01d8a79d4e2a2348ece
|
|
BLAKE2b-256 checksum How to use checksums |
1ab1dcc2fa49d481ca89454725a4218c8cc6a4e7e9280825c33c6a045199ca6f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / monlite-0.2.0-py3-none-any.whl
| Download URL | monlite-0.2.0-py3-none-any.whl |
|---|---|
| Size | 36.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
29b41b712fd1e671388b3f5000a9fb7553c514b92acc8a4f3a554c8e36b25b79
|
|
BLAKE2b-256 checksum How to use checksums |
569f196ea1f11567fb18add177cbfa8906ac5b7302425a7805d383eec4e549e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|