Embedded database for Python · MIT
The Swiss army knife of local data.
Dicts, lists, queues, logs, searchable documents, vectors, graphs, blobs, locks and channels, all in one SQLite file. No server to run, nothing to configure.
$ pip install beaver-dbv2.4.1 · Python 3.12+ · MIT

One file, many shapes
Pick the shape your data has.
Each manager is a name inside the same app.db. Every snippet below runs as is after pip install beaver-db.
from beaver import BeaverDB db = BeaverDB("app.db") config = db.dict("config") config["theme"] = "dark" config.set("session", {"user": "ana"}, ttl_seconds=3600) print(config["theme"], len(config))
dark 2
from beaver import BeaverDB db = BeaverDB("app.db") todo = db.list("todo") todo.push("write the report") todo.push("ship the release") todo.prepend("buy coffee") print(todo[0], todo[1:], len(todo))
buy coffee ['write the report', 'ship the release'] 3
from beaver import BeaverDB db = BeaverDB("app.db") jobs = db.queue("jobs") jobs.put({"task": "resize", "file": "a.png"}, priority=2) jobs.put({"task": "urgent"}, priority=1) job = jobs.get() # lowest priority value first print(job.data)
{'task': 'urgent'}
import time from beaver import BeaverDB db = BeaverDB("app.db") metrics = db.log("metrics") metrics.log({"cpu": 0.42, "host": "web-1"}) metrics.log({"cpu": 0.57, "host": "web-2"}) last_hour = metrics.range(start=time.time() - 3600) print(len(last_hour), last_hour[-1].data)
2 {'cpu': 0.57, 'host': 'web-2'}
from beaver import BeaverDB, Document db = BeaverDB("app.db") notes = db.docs("notes") notes.index(Document(id="wal", body="readers and writers share one file"), fuzzy=True) notes.index(Document(id="aio", body="asyncio runs coroutines"), fuzzy=True) print([h.document.id for h in notes.search("readers")]) # full-text print([h.document.id for h in notes.search("corutines", fuzzy=True)]) # typo-tolerant
['wal']
['aio']
from beaver import BeaverDB db = BeaverDB("app.db") emb = db.vectors("embeddings") emb.set("cat", [0.9, 0.1, 0.0]) emb.set("dog", [0.8, 0.2, 0.1]) emb.set("car", [0.0, 0.1, 0.9]) for item in emb.near([0.85, 0.15, 0.05], k=2): print(item.id)
cat
dog
from beaver import BeaverDB db = BeaverDB("app.db") g = db.graph("people") g.link("ana", "ben", "knows") g.link("ben", "cara", "knows") g.link("ana", "acme", "works_at") print(list(g.children("ana", label="knows"))) print(list(g.parents("cara")))
['ben']
['ben']
from beaver import BeaverDB db = BeaverDB("app.db") files = db.blob("files") files.put("logo.png", b"\x89PNG...", metadata={"type": "image/png"}) item = files.fetch("logo.png") print(len(item.data), item.metadata)
7 {'type': 'image/png'}
from beaver import BeaverDB db = BeaverDB("app.db") # coordinates threads and processes that share app.db with db.lock("nightly-backup", timeout=5): print("only this process runs the backup")
only this process runs the backup
import threading from beaver import BeaverDB db = BeaverDB("app.db") chat = db.channel("chat") def listen(): for msg in chat.listen(): # any process with app.db can listen print("got", msg.payload) break t = threading.Thread(target=listen); t.start() chat.publish({"from": "ana", "text": "hello"}) t.join(timeout=5)
got {'from': 'ana', 'text': 'hello'}
The file is standard SQLite: open it with any SQLite tool. Python's own sqlite3 module reads all its tables.
Grows with you
Start with a script. Keep the file.
1A script
Open a file and use it. The same API exists as async, with await.
db = BeaverDB("app.db")2Many processes
Workers share app.db: a queue hands out jobs, a lock keeps one-at-a-time work, a channel tells the others.
jobs = db.queue("jobs")3The shell
Read and write dicts, lists, queues and logs from the command line.
beaver --db app.db dict config get theme4Over the network
Serve the file over REST and connect with the same API. Dicts, lists, queues and logs today.
beaver serve --db app.db --api-key "$KEY"beaver.connect(url, api_key=key)Deployment guide →Always start beaver serve with --api-key. Without it the server has no authentication, so keep it on 127.0.0.1 (the default).
What's in the box
Twelve tools, one handle.
DictsKey-value with namespaces and per-key TTL.
ListsPush, pop, prepend, insert, slices.
QueuesPriority queue shared across processes.
LogsTime-indexed entries, range queries, a live view.
DocumentsFull-text search on SQLite FTS5, plus fuzzy matching.
VectorsNearest neighbours, exact or with an LSH index.
GraphsLabelled edges, children and parents.
BlobsBinary files with JSON metadata.
LocksNamed locks across processes, with a TTL.
ChannelsPublish and subscribe between processes.
SketchesHyperLogLog counts and Bloom filters in fixed space.
PydanticAttach a model to any structure for validation.