pickleDB is a lightweight, JSON-backed key-value store for Python, designed for
simple APIs, fast in-memory operations, and a
unified sync/async interface. BSD 3-Clause License · © Harrison Erd.
pip install pickledb
from pickledb import PickleDB
# Bind to a JSON file; no I/O yet
db = PickleDB("data.json").load() # load from disk into memory (if file exists)
db.set("username", "alice")
db.set("theme", {"color": "blue", "font": "sans-serif"})
print(db.get("username")) # → "alice"
db.save() # atomically write in-memory DB back to data.json
import asyncio
from pickledb import PickleDB
async def main():
db = await PickleDB("data.json").load()
await db.set("score", 42)
value = await db.get("score")
print(value) # → 42
await db.save()
asyncio.run(main())
PickleDB("data.json") never touches disk.
load() and save() are explicit (or handled by context managers).
set(), get(), remove(), etc.os.replace to avoid partial writes.save() or exit a context manager cleanly.from pickledb import PickleDB
with PickleDB("data.json") as db:
# On enter: db.load()
db.set("foo", "bar")
db.set("hello", "world")
# On successful exit: db.save()
import asyncio
from pickledb import PickleDB
async def main():
async with PickleDB("data.json") as db:
# On enter: await db.load()
await db.set("foo", "bar")
await db.set("hello", "world")
# On successful exit: await db.save()
asyncio.run(main())
These are the only methods you really need to know. Every method works the same in sync and async code;
just add await when you’re in an async function. All of these methods are part of the PickleDB class.
| Method | Sync usage | Async usage | Description |
|---|---|---|---|
load() |
db.load() |
await db.load() |
Load (or reload) the JSON file into memory. Returns the same PickleDB instance for chaining. |
save() |
db.save() |
await db.save() |
Atomically save the in-memory database back to disk. |
set(key, value) |
db.set(k, v) |
await db.set(k, v) |
Store a value under key. Keys are coerced to str; values must be JSON-serializable. |
get(key, default=None) |
db.get(k, d) |
await db.get(k, d) |
Retrieve the stored value, or default if the key doesn’t exist. |
remove(key) |
db.remove(k) |
await db.remove(k) |
Delete a key. Returns True if it existed and was removed. |
all() |
db.all() |
await db.all() |
Return a list of all keys in the in-memory database. |
purge() |
db.purge() |
await db.purge() |
Clear the in-memory database. Returns True. |
pickleDB is intentionally method-based only. Dict-style access like
db["key"] or db["key"] = value is not supported.
# Store a dictionary
db.set("user", {"name": "Alice", "age": 30})
# Update it
user = db.get("user")
user["age"] += 1
db.set("user", user)
print(db.get("user"))
# {'name': 'Alice', 'age': 31}
db.set("tasks", ["write", "test", "deploy"])
tasks = db.get("tasks", [])
tasks.append("celebrate")
db.set("tasks", tasks)
print(db.get("tasks"))
# ['write', 'test', 'deploy', 'celebrate']
db.set("user:1", {"name": "Alice"})
db.set("user:2", {"name": "Bob"})
def keys_with_prefix(db, prefix):
return [k for k in db.all() if k.startswith(prefix)]
print(keys_with_prefix(db, "user:"))
# ['user:1', 'user:2']
import time
def set_with_ttl(db, key, value, ttl_seconds):
db.set(key, {
"value": value,
"expires_at": time.time() + ttl_seconds,
})
def get_if_fresh(db, key):
data = db.get(key)
if not data:
return None
if time.time() < data.get("expires_at", 0):
return data["value"]
db.remove(key)
return None
set_with_ttl(db, "session", "active", ttl_seconds=5)
time.sleep(3)
print(get_if_fresh(db, "session")) # 'active'
time.sleep(3)
print(get_if_fresh(db, "session")) # None
Example timings loading, reading, and saving large JSON payloads using async mode on a Dell XPS 9350, Ubuntu 24.04:
| Entries | Load (into memory) | Bulk read | Save (to disk) |
|---|---|---|---|
| 1M | 0.68 s | 0.64 s | 0.03 s |
| 10M | 7.48 s | 7.27 s | 0.22 s |
| 50M | 43.36 s | 36.53 s | 1.09 s |
Full benchmark script: available here.
In those cases, consider Redis or MongoDB instead.
Issues, questions, or ideas? Open an issue on GitHub.