patx/pickledb
pickleDB is an in memory key-value store using Python's orjson module for persistence. It can also use SQLite instead of orjson if needed. This is an official mirror of pickleDB, for issue tracking and contributions see the official repo on GitHub!
$ git clone https://gitman.io/git/patx/pickledb
pickleDB: Your Lightweight, High-Speed Key-Value Store
pickleDB is a lightweight, in-memory key-value store designed for developers who want simplicity, speed, and reliability — without sacrificing modern capabilities. BSD 3-Clause License © Harrison Erd.
- 💫 Blazing Speed: Backed by the high-performance orjson library, pickleDB handles millions of records with ease. Perfect for applications where every millisecond counts
- 😋 Ridiculously Easy to Use: With its minimalist API, pickleDB makes adding, retrieving, and managing your data as simple as writing a Python list. No steep learning curves. No unnecessary complexity.
- 🔒 Rock-Solid Reliability: Your data deserves to be safe. Atomic saves ensure your database remains consistent—even if something goes wrong.
- 🐍 Simple Pythonic Flexibility: Store strings, lists, dictionaries, and more—all with native Python operations. No need to learn special commands. If you know Python, you already know pickleDB.
- 🙋 Community & Contributions: We’re passionate about making pickleDB better every day. Got ideas, feedback, or an issue to report? Let’s connect on GitHub Issues
- 💾 Portable: Data is stored as standard JSON, human-readable and cross-language friendly.
- 🕸️ Async-Ready: Non-blocking I/O with aiofiles. Works with web frameworks like Starlette, FastAPI, or MicroPie.
- ⚡ Unified API: One class, one set of methods - works seamlessly in both sync and async environments.
- 💢 Limitations: The entire dataset resides in memory while loaded which might be a constraint on systems with limited RAM for extremely large datasets. pickleDB is designed for simplicity, so it may not meet the needs of applications requiring advanced database features. For larger-scale or concurrent applications requiring a more robust, consider DataSet, Redis, SQLite, or MongoDB.
- 📎 Useful Links: GitHub - PyPI - Report an Issue/Ask for Help - Documentation
Getting Started
Installation
Install via pip:
pip install pickledb
Synchronous Example
from pickledb import PickleDB
db = PickleDB("data.json")
db.load()
db.set("username", "alice")
db.set("theme", {"color": "blue", "font": "sans-serif"})
print(db.get("username")) # → "alice"
db.save()
Asynchronous Example
import asyncio
from pickledb import PickleDB
async def main():
async with PickleDB("data.json") as db:
await db.set("score", 42)
value = await db.get("score")
print(value) # → 42
asyncio.run(main())
Core Methods
| Method | Description |
|---|---|
load() |
Loads the database from disk (async-aware). |
save() |
Atomically saves the database to disk. |
set(key, value) |
Sets or updates a key. |
get(key, default=None) |
Returns the value for a key. |
remove(key) |
Deletes a key if it exists. |
all() |
Returns a list of all keys. |
purge() |
Clears the entire database. |
All of these methods can be used synchronously or asynchronously — just await them if inside an event loop.
Performance Highlights
pickleDB demonstrates strong performance for handling large-sized datasets:
| Entries | Memory Load Time | Retrieval Time | Save Time |
|---|---|---|---|
| 1M | 0.68 sec | 0.64 sec | 0.03 sec |
| 10M | 7.48 sec | 7.27 sec | 0.22 sec |
| 50M | 43.36 sec | 36.53 sec | 1.09 sec |
Tests were performed on a Dell XPS 9350 running Ubuntu 24.04 using pickleDB's async mode.
User Guide and Examples
Add or Update Data
You can add or update key-value pairs using the set() method:
# Add a new key-value pair
db.set('username', 'admin')
# Or shorthand
db['username'] = 'admin'
# Update an existing key-value pair
db.set('username', 'superadmin')
print(db.get('username')) # Output: 'superadmin'
Keys are automatically converted to strings, and values can be any JSON-serializable object.
Retrieve Values
You can retrieve a keys value using the get() method:
# Get the value for a key
print(db.get('username')) # Output: 'superadmin'
# Using Python syntax sugar
db['username'] # Output: 'superadmin'
# Attempt to retrieve a non-existent key
print(db.get('nonexistent')) # Output: None
List All Keys
You can get a list of all the keys currently in the database using the all() method:
db.set('item1', 'value1')
db.set('item2', 'value2')
print(db.all()) # Output: ['username', 'item1', 'item2']
Note: This method shows all keys currently loaded, it does not guarantee they are persisted to the disk (yet).
Remove Keys
To remove a key from the database use the remove() method:
db.remove('item1')
print(db.all()) # Output: ['username', 'item2']
Purge the Database
To remove all keys and their values from the database use the purge() method:
db.purge()
print(db.all()) # Output: []
Saving Data
pickleDB does not auto-save by default for performance reasons. To persist data, call save() manually or use a context manager:
db.save() # Output: True
# Context manager example
with db:
db.set('foo', 'bar')
db.set('hello', 'world')
# Automatically saves when exiting the context
Note: All the above methods work/display on the in-memory database. To persist any of the above methods actions use must call the save() method or use a context manager, as stated above.
Asynchronous Usage
pickleDB 1.4 uses a single unified class for both synchronous and asynchronous contexts.
import asyncio
from pickledb import PickleDB
async def main():
async with PickleDB('data.json') as db:
await db.set('score', 42)
print(await db.get('score')) # Output: 42
asyncio.run(main())
Just await any method when inside an async function/event-loop.
Store and Retrieve Complex Data
# Store a dictionary
db.set('user', {'name': 'Alice', 'age': 30, 'city': 'Wonderland'})
# Retrieve and modify
user = db.get('user')
user['age'] += 1
db.set('user', user)
print(db.get('user'))
# Output: {'name': 'Alice', 'age': 31, 'city': 'Wonderland'}
Use Lists for Dynamic Data
db.set('tasks', ['Write code', 'Test app', 'Deploy'])
tasks = db.get('tasks')
tasks.append('Celebrate')
db.set('tasks', tasks)
print(db.get('tasks'))
# Output: ['Write code', 'Test app', 'Deploy', 'Celebrate']
Advanced Key Search
You can filter keys dynamically using Python list comprehensions:
def get_keys_with_match(db_instance, match):
return [key for key in db_instance.all() if match in key]
db.set('apple', 1)
db.set('apricot', 2)
db.set('banana', 3)
print(get_keys_with_match(db, 'ap'))
# Output: ['apple', 'apricot']
Namespaces
Simulate namespaces using prefixes:
db.set('user:1', {'name': 'Alice'})
db.set('user:2', {'name': 'Bob'})
def get_namespace_keys(db_instance, namespace):
return [key for key in db_instance.all() if key.startswith(f"{namespace}:")]
print(get_namespace_keys(db, 'user'))
# Output: ['user:1', 'user:2']
Key Expiration (TTL)
pickleDB doesn’t include TTL natively, but you can simulate it:
import time
def set_with_expiry(db, key, value, ttl):
db.set(key, {'value': value, 'expires_at': time.time() + ttl})
def get_if_not_expired(db, key):
data = db.get(key)
if data and time.time() < data['expires_at']:
return data['value']
db.remove(key)
return None
set_with_expiry(db, 'session', 'active', ttl=5)
time.sleep(3)
print(get_if_not_expired(db, 'session')) # 'active'
time.sleep(3)
print(get_if_not_expired(db, 'session')) # None
Encrypted Storage
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
encrypted = cipher.encrypt(b"My secret data")
db.set('secure', encrypted)
decrypted = cipher.decrypt(db.get('secure'))
print(decrypted.decode()) # Output: My secret data
Batch Operations
def batch_set(db, items):
for key, value in items.items():
db.set(key, value)
batch_set(db, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})
print(db.all())
def batch_delete(db, keys):
for key in keys:
db.remove(key)
batch_delete(db, ['k1', 'k2'])
print(db.all())
Key Pattern Matching
import re
def get_keys_by_pattern(db, pattern):
regex = re.compile(pattern)
return [key for key in db.all() if regex.search(key)]
db.set('user:1', {'name': 'Alice'})
db.set('user:2', {'name': 'Bob'})
db.set('admin:1', {'name': 'Charlie'})
print(get_keys_by_pattern(db, r'user:\d'))
# Output: ['user:1', 'user:2']
Signal Handling for Graceful Shutdowns
import signal, sys
from pickledb import PickleDB
db = PickleDB('data.json')
signal.signal(signal.SIGINT, lambda s, f: (db.save(), sys.exit(0)))
signal.signal(signal.SIGTERM, lambda s, f: (db.save(), sys.exit(0)))
db.set('key1', 'value1')
print("Running... Press Ctrl+C to save and exit.")
while True:
pass
Using pickleDB with Web Frameworks
Example using MicroPie:
from uuid import uuid4
from micropie import App
from pickledb import PickleDB
db = PickleDB('pastes.json')
class Root(App):
async def index(self, paste_content=None):
if self.request.method == "POST":
pid = str(uuid4())
await db.set(pid, paste)
await db.save()
return self._redirect(f'/paste/{pid}')
return await self._render_template('index.html')
async def paste(self, paste_id):
paste = await db.get(paste_id)
return await self._render_template('paste.html', paste_id=paste_id, paste_content=paste)
app = Root()
Core API Reference
Class: PickleDB
class PickleDB(location: str)
A lightweight, JSON-backed key-value database. All data is kept in memory while loaded and written atomically to disk on save().
Parameters
| Name | Type | Description |
|---|---|---|
location |
str |
Path to the JSON file backing the database. Tilde (~) is expanded. |
Context Manager Support
Synchronous
with PickleDB("data.json") as db:
db.set("foo", "bar")
Asynchronous
async with PickleDB("data.json") as db:
await db.set("foo", "bar")
On successful exit, the DB is automatically saved.
Method Reference
load()
load() -> None
await load() -> None
Loads the database into memory from disk if the file exists and contains valid JSON. Creates an empty database otherwise.
save()
save() -> bool
await save() -> bool
Writes the in-memory database to disk.
Returns True on success.
Notes:
- Uses a temporary file + os.replace for durability.
- Automatically called on successful context-manager exit.
set()
set(key: str, value: Any) -> bool
await set(key: str, value: Any) -> bool
Sets or updates a value for a key.
key is coerced to str, and value must be JSON-serializable.
Returns True.
Syntax Sugar
db["username"] = "alice"
get()
get(key: str, default: Any = None) -> Any
await get(key: str, default: Any = None) -> Any
Retrieves a value by key.
Returns:
- stored value
- default if key does not exist
Syntax Sugar
value = db["username"]
remove()
remove(key: str) -> bool
await remove(key: str) -> bool
Removes a key.
Returns:
- True if removed
- False if not found
all()
all() -> list[str]
await all() -> list[str]
Returns a list of all keys currently in memory.
purge()
purge() -> bool
await purge() -> bool
Clears the entire in-memory database.
Returns:
- True
Synchronous vs Asynchronous Behavior
All public methods of PickleDB work in both runtimes:
| Environment | Usage |
|---|---|
| Synchronous | db.load() |
| Asynchronous | await db.load() |
Internally, the library detects whether it is inside an async event loop.
