Storage Backends
PraisonAI provides pluggable storage backends for training data, session state, and general persistence. Switch between file-based and database storage without changing your application code.Supported Backends
Quick Start
Any Component with Any Backend
All storage components support pluggable backends. Create a backend once and use it with any component:FileBackend
JSON file-based storage. Each key becomes a separate.json file.
- Zero dependencies (uses built-in
json) - Thread-safe with atomic writes — a failed
save()(serialization error, encoding error, oros.replacefailure) leaves the previous store intact and removes the staging.tmpfile. See Thread Safety → BaseJSONStore atomic save. - Human-readable files
- Easy debugging and inspection
Failure Modes
FileBackend.save is all-or-nothing: either the destination file is replaced with the new content, or it stays exactly as it was before the call.
No partial files are left behind on any failure path, so re-running the save after fixing the data is safe — the storage directory never fills up with orphaned staging files.
Error Handling
load() never raises on a corrupted file — it logs a warning and returns None. Your agent keeps running and other keys keep loading.
load() is non-destructive — a corrupted file is left on disk so you can inspect or restore it. To clear a bad key, call backend.delete(key) explicitly.Save-side guard: an unreadable key cannot be overwritten by ordinary saves
Oncebackend.load(key) observes a decode failure on a key (invalid UTF-8, malformed JSON, or IOError), the same backend instance refuses an ordinary backend.save(key, data) while the unreadable file is still on disk. Neighbouring, readable keys stay fully usable — the guard is per-path.
Writes to other keys are never affected.
This guard exists so a transient-looking fallback (
load() → None) never silently clobbers forensic evidence on disk. Repair the file (restore, re-encode) or delete it explicitly before writing again.SQLiteBackend
SQLite database storage. All data in a single.db file.
- Zero dependencies (uses built-in
sqlite3) - ACID transactions
- Better concurrent access
- Faster for large datasets
- Single file deployment
Table name rules
table_name accepts letters, digits, and underscores only. The default is praison_storage.
SQL keywords and digit-leading names are safe. The backend quotes the identifier internally ("select", "9table"), so names like select, order, 9table, or 123 work with nothing extra required.
ValueError before any SQL runs. SQLite itself also reserves object names starting with sqlite_, which it refuses regardless of this backend.
Different table_name values map to different, isolated tables in the same .db file — useful for sharing one database across stores without separate files.
table_name is validated at construction and then used as a quoted SQLite identifier ("table_name") in every statement, so SQL keywords and digit-leading names are safe. Only names matching [a-zA-Z0-9_]+ are accepted; anything else raises ValueError before any SQL runs. SQLite’s own sqlite_ prefix restriction still applies — see Construction failure modes for what happens when a reserved name slips past validation.Construction failure modes
WhenSQLiteBackend(...) raises during construction, the opened SQLite connection is closed before the error propagates, and the database file is left exactly as it was before the call.
This makes construction safe to retry — inspect or replace the
.db file, fix the offending argument, and reconstruct.
SQLiteBackend(..., auto_create=False) skips schema creation entirely, so none of these schema-init paths run. Validation of table_name still applies.Using with Training Storage
TrainingStorage is a context manager — use with to close the backend deterministically.
Using
with (or calling .close() explicitly) releases the underlying SQLite or Redis
connection so the file can be deleted or reopened immediately — essential on Windows, and
best practice for long-running processes. On backends without an open resource (e.g.
FileBackend) .close() is a safe no-op.SQLiteBackend (or RedisBackend) directly — for example via
list_sessions_from_backend(SQLiteBackend(db_path=db)) — close the backend
yourself, or wrap the call in try / finally. TrainingStorage’s context
manager only closes backends it owns.
Using with Learn Stores
Async Support
For async applications, useAsyncBaseJSONStore:
Custom Backends
ImplementStorageBackendProtocol for custom backends:
Protocol Reference
RedisBackend
Redis-based storage for high-speed caching and ephemeral data.- Sub-millisecond latency
- Built-in TTL support
- Automatic key prefixing
- Requires
redispackage:pip install redis
Using with RunHistory (Recipe History)
Store recipe run history with pluggable backends:Using with SessionManager (Session State)
Persist CLI session state with different backends:Using with MCPToolIndex (Tool Index)
Store MCP tool schemas with pluggable backends:Choosing a Backend
Backend Comparison
Related
Database Overview
All supported databases
Memory Storage
Agent memory persistence
Training
Agent training with storage
Session Resume
Continue conversations

