Stores¶
Stores are the core implementations of the AsyncKeyValue protocol. They provide
the actual storage backend for your key-value data.
Concurrent Setup¶
Lazy store and collection setup is coordinated across threads and event loops, so concurrent first use does not initialize the same resource twice. Individual client libraries can still impose their own thread or event-loop ownership requirements; check the backend's documentation before sharing a networked store between event loops.
Store Categories¶
Stores are organized into three categories based on their storage location and use case:
- Local Stores: In-memory or on-disk storage local to the application
- Secret Stores: Secure storage for sensitive data in OS secret stores
- Distributed Stores: Network-based storage for multi-node applications
Stability Levels¶
Each store has a stability rating that indicates the likelihood of backwards-incompatible changes to how data is stored:
- Stable: No planned backwards-incompatible changes
- Preview: Unlikely to change in backwards-incompatible ways
- Unstable: May change in backwards-incompatible ways
- N/A: Not applicable (e.g., in-memory stores)
If you're using py-key-value for caching, stability may not matter. For long-term storage, prefer stable stores.
Local Stores¶
Local stores are stored in memory or on disk, local to the application.
| Store | Stability | Description |
|---|---|---|
| Memory | N/A | Fast in-memory storage for development and caching |
| Disk | Stable | Persistent file-based storage in a single file |
| Disk (Per-Collection) | Stable | Persistent storage with separate files per collection |
| DuckDB | Unstable | In-process SQL OLAP database with native JSON storage |
| chDB | Unstable | Embedded ClickHouse engine with SQL access to stored data |
| FileTree | Stable | Directory-based storage with JSON files for visual inspection |
| Null (test) | N/A | No-op store for testing without side effects |
| RocksDB | Unstable | High-performance embedded database |
| Simple (test) | N/A | Simple in-memory store for testing |
| Windows Registry | Unstable | Windows Registry-based storage |
MemoryStore¶
Fast in-memory storage ideal for development, testing, and caching.
Installation:
Use Cases:
- Development and testing
- Fast caching
- Session storage
- Temporary data
Characteristics:
- No persistence (data lost on restart)
- Extremely fast
- No external dependencies
- Safe for concurrent async tasks; create separate instances for cross-thread use
DiskStore¶
Persistent file-based storage using a single JSON file.
Installation:
Use Cases:
- Local caching with persistence
- Development environments
- Single-node applications
- Small datasets
Characteristics:
- Persists across restarts
- Simple file format (JSON)
- Suitable for small to medium datasets
- All data in one file
MultiDiskStore¶
Persistent storage with separate files per collection.
from key_value.aio.stores.multi_disk import MultiDiskStore
store = MultiDiskStore(directory="./cache")
Installation:
Use Cases:
- Organizing data by collection
- Better performance with many collections
- Easier to manage individual collections
Characteristics:
- One file per collection
- Better suited for many collections
- Easier collection management
- JSON-based storage
FileTreeStore¶
Directory-based storage for visual inspection and debugging.
from key_value.aio.stores.filetree import FileTreeStore
store = FileTreeStore(directory="./debug-store")
Installation:
Use Cases:
- Visual inspection of store contents
- Debugging store behavior
- Development and testing
- Understanding data structure
Characteristics:
- Collections as directories
- Keys as JSON files (
{key}.json) - Human-readable filesystem layout
- Easy to inspect and modify
- NOT for production use
Directory Structure:
Important Limitations:
- Poor performance with many keys
- No atomic operations
- No automatic cleanup of expired entries
- Filesystem path length constraints
- Subject to filesystem limitations
When to Use:
Use FileTreeStore when you need to:
- Visually inspect what's being stored
- Debug complex data structures
- Understand how the store organizes data
- Manually modify stored data for testing
When NOT to Use:
- Production environments
- High-performance requirements
- Large datasets
- Concurrent access scenarios
DuckDBStore¶
In-process SQL OLAP database with native JSON storage.
from key_value.aio.stores.duckdb import DuckDBStore
# In-memory database (default)
store = DuckDBStore()
# Persistent database
store = DuckDBStore(database_path="./my_store.duckdb")
# With existing connection
import duckdb
connection = duckdb.connect("./my_store.duckdb")
store = DuckDBStore(connection=connection)
Installation:
Use Cases:
- Analytics on stored key-value data
- Local development with SQL querying capabilities
- Applications needing both key-value and SQL access
- Data exploration and reporting
Characteristics:
- Native JSON column support for queryable values
- In-memory or persistent storage
- Standard SQL access to stored data
- Efficient timestamp handling for TTL queries
- Stable storage format: Unstable
Direct SQL Access:
DuckDB allows you to query your key-value data directly with SQL:
# After storing some data
await store.put("user:1", {"name": "Alice", "age": 30}, collection="users")
await store.put("user:2", {"name": "Bob", "age": 25}, collection="users")
# Query directly via DuckDB
result = store._connection.execute("""
SELECT key, value->>'name' as name
FROM kv_entries
WHERE collection = 'users'
""").fetchall()
ChDBStore¶
Embedded ClickHouse engine (chDB) with SQL access to your key-value data.
from key_value.aio.stores.chdb import ChDBStore
# In-memory database (default)
store = ChDBStore()
# Persistent database (chDB stores data in a directory)
store = ChDBStore(database_path="./my_store.chdb")
# With an existing chDB session
from chdb.session import Session
session = Session("./my_store.chdb")
store = ChDBStore(session=session)
Installation:
Use Cases:
- Analytics on stored key-value data with full ClickHouse SQL
- Embedded OLAP workloads alongside cache-style usage
- Applications needing both key-value access and ClickHouse functions
Characteristics:
- Embedded ClickHouse — no external server required
- In-memory or persistent storage (single directory)
- Process-global singleton: only one
database_pathactive per process at a time - Full ClickHouse SQL on stored data
- ReplacingMergeTree-backed schema (latest write wins via
FINAL) - Synchronous I/O (chDB has no async API; operations block the event loop)
- Expired entries are not automatically culled — see class docstring for cleanup guidance
- Stable storage format: Unstable
RocksDBStore¶
High-performance embedded database using RocksDB.
Installation:
Use Cases:
- High-throughput applications
- Large datasets
- Performance-critical applications
Characteristics:
- Very fast reads and writes
- Efficient storage
- Requires native dependencies
- Stable storage format: Unstable
WindowsRegistryStore¶
Storage using the Windows Registry.
from key_value.aio.stores.registry import WindowsRegistryStore
store = WindowsRegistryStore(
hive="HKEY_CURRENT_USER",
registry_path="Software\\py-key-value"
)
Installation:
Use Cases:
- Windows-specific applications
- System configuration storage
- Integration with Windows settings
Characteristics:
- Windows-only
- Persists in registry
- Subject to registry limitations
- Stable storage format: Unstable
NullStore¶
No-op store that discards all data. Useful for testing.
Use Cases:
- Testing without side effects
- Disabling storage temporarily
- Performance baseline testing
SimpleStore¶
Simple in-memory store for testing.
Use Cases:
- Basic testing
- Minimal implementation reference
Secret Stores¶
Secret stores provide secure storage for sensitive data, typically using operating system secret management facilities.
| Store | Stability | Description |
|---|---|---|
| Keyring | Stable | OS-level secure storage (Keychain, Credential Manager, etc.) |
| Vault | Unstable | HashiCorp Vault integration for enterprise secrets |
KeyringStore¶
Secure storage using the operating system's keyring (macOS Keychain, Windows Credential Manager, Linux Secret Service).
from key_value.aio.stores.keyring import KeyringStore
store = KeyringStore(service_name="py-key-value")
Installation:
Use Cases:
- Storing API keys and tokens
- User credentials
- Sensitive configuration
- Encrypted local storage
Characteristics:
- OS-level encryption
- Secure by default
- Cross-platform
- Windows limitation: Strict value length limits
Important: Windows Keyring has strict limits on value length which may cause issues with large values.
VaultStore¶
Integration with HashiCorp Vault for enterprise secret management.
from key_value.aio.stores.vault import VaultStore
store = VaultStore(
url="http://localhost:8200",
token="your-token"
)
Installation:
Use Cases:
- Enterprise secret management
- Multi-environment deployments
- Centralized secret rotation
- Audit logging
Characteristics:
- Enterprise-grade security
- Centralized management
- Audit logging
- Stable storage format: Unstable
Distributed Stores¶
Distributed stores provide network-based storage for multi-node applications.
| Store | Stability | Description |
|---|---|---|
| Aerospike | Unstable | High-performance distributed NoSQL database |
| Azure Tables | Unstable | Azure Table Storage key-value storage |
| DynamoDB | Unstable | AWS DynamoDB key-value storage |
| S3 | Unstable | AWS S3 object storage |
| Elasticsearch | Unstable | Full-text search with key-value capabilities |
| Firestore | Unstable | Google Cloud Firestore key-value storage |
| Memcached | Unstable | High-performance distributed memory cache |
| MongoDB | Unstable | Document database used as key-value store |
| OpenSearch | Unstable | OpenSearch search engine with key-value capabilities |
| PostgreSQL | Unstable | PostgreSQL database with JSONB storage |
| Redis | Stable | Popular in-memory data structure store |
| Valkey | Stable | Open-source Redis fork |
AerospikeStore¶
High-performance distributed NoSQL database optimized for speed and scale.
from key_value.aio.stores.aerospike import AerospikeStore
# Using host list
store = AerospikeStore(
hosts=[("localhost", 3000)],
namespace="test",
set_name="kv-store"
)
# Or with an existing client
import aerospike
client = aerospike.client({"hosts": [("localhost", 3000)]})
client.connect()
store = AerospikeStore(client=client, namespace="test")
Installation:
Use Cases:
- High-throughput applications
- Real-time data processing
- Large-scale distributed systems
- Low-latency caching
Characteristics:
- Sub-millisecond latency
- Horizontal scaling
- Native TTL support
- Namespaces must be pre-configured on server
- Sets created automatically
- Stable storage format: Unstable
RedisStore¶
High-performance in-memory store using Redis.
from key_value.aio.stores.redis import RedisStore
store = RedisStore(url="redis://localhost:6379/0")
tls_store = RedisStore(
url="rediss://redis.example.com:6380/0",
ssl_ca_certs="/etc/ssl/certs/redis-ca.pem",
)
Redis TLS can be enabled with a rediss:// URL or with ssl=True when using
host and port. Pass ssl_ca_certs to verify the server certificate, and
ssl_certfile plus ssl_keyfile for mutual TLS deployments. For development
or test environments with self-signed certificates, ssl_cert_reqs="none" and
ssl_check_hostname=False are available, but should not be used for production.
Installation:
Use Cases:
- Distributed caching
- Session storage
- Real-time applications
- High-throughput systems
Characteristics:
- Very fast (in-memory)
- Production-ready
- Rich feature set
- Horizontal scaling support
- SSL/TLS and mutual TLS connection options
- Stable storage format
ValkeyStore¶
Open-source Redis fork with similar performance characteristics.
from key_value.aio.stores.valkey import ValkeyStore
store = ValkeyStore(host="localhost", port=6379)
For Valkey Cluster deployments, pass a GLIDE cluster configuration. The store
will create the GlideClusterClient lazily on first use, so applications can
configure the store before an async event loop is running:
from glide_shared.config import GlideClusterClientConfiguration, NodeAddress
from key_value.aio.stores.valkey import ValkeyStore
cluster_store = ValkeyStore(
config=GlideClusterClientConfiguration(
addresses=[NodeAddress("valkey-cluster.example.com", 6379)]
)
)
Installation:
Use Cases:
- Same as Redis
- Open-source preference
- Redis API compatibility
Characteristics:
- Redis-compatible
- Open-source governance
- Production-ready
- Standalone and cluster-mode GLIDE clients
- Stable storage format
FirestoreStore¶
Google Cloud Firestore used as a key-value store.
from key_value.aio.stores.firestore import (
FirestoreStore,
FirestoreV1CollectionSanitizationStrategy,
FirestoreV1KeySanitizationStrategy,
)
store = FirestoreStore(
credentials=google_credentials,
database="firestore-db",
key_sanitization_strategy=FirestoreV1KeySanitizationStrategy(),
collection_sanitization_strategy=FirestoreV1CollectionSanitizationStrategy(),
)
Installation:
Use Cases:
- Google Cloud-native applications
- Serverless / managed infrastructure
- Existing Firestore deployments
Characteristics:
- Managed cloud database
- Document/collection model
- Optional key and collection sanitization for Firestore ID constraints
- Firestore sanitizers reserve
H_andS_prefixes for keys and collections to prevent collisions - Stable storage format: Unstable
AzureTablesStore¶
Azure Table Storage integration for Azure-native applications.
from key_value.aio.stores.azure_tables import (
AzureTablesSanitizationStrategy,
AzureTablesStore,
)
store = AzureTablesStore(
account_name="mystorageaccount",
credential=credential,
table_name="kvstore",
collection_sanitization_strategy=AzureTablesSanitizationStrategy(),
key_sanitization_strategy=AzureTablesSanitizationStrategy(),
)
Installation:
Use Cases:
- Azure-native applications
- Serverless / managed infrastructure
- Low-cost persistent state
- Managed Identity authentication
- OAuth/session state on Azure Container Apps
Characteristics:
- Fully managed
- Pay-per-use pricing
- No native background TTL; entries are lazily expired on read
- Optional PartitionKey/RowKey sanitization for Azure Tables limits
- Stable storage format: Unstable
DynamoDBStore¶
AWS DynamoDB integration for serverless and cloud-native applications.
from key_value.aio.stores.dynamodb import DynamoDBStore
store = DynamoDBStore(
table_name="kv-store",
region_name="us-east-1"
)
Installation:
Use Cases:
- AWS-native applications
- Serverless architectures
- Global distribution
- Managed infrastructure
Characteristics:
- Fully managed
- Auto-scaling
- Global tables
- Pay-per-use pricing
- Stable storage format: Unstable
S3Store¶
AWS S3 object storage for durable, scalable key-value storage.
from key_value.aio.stores.s3 import S3Store
store = S3Store(
bucket_name="my-kv-bucket",
region_name="us-east-1"
)
Installation:
Use Cases:
- Large value storage (up to 5TB per object)
- Durable, long-term storage
- Cost-effective archival
- Multi-region replication
Characteristics:
- 99.999999999% durability
- Automatic key sanitization for S3 path limits
- Supports lifecycle policies
- Pay-per-use pricing
- Stable storage format: Unstable
ElasticsearchStore¶
Full-text search engine used as a key-value store.
from key_value.aio.stores.elasticsearch import ElasticsearchStore
store = ElasticsearchStore(
url="https://localhost:9200",
api_key="your-api-key",
index="kv-store"
)
Installation:
Use Cases:
- Applications already using Elasticsearch
- Need for search capabilities
- Analytics and logging
Characteristics:
- Search capabilities
- Distributed by default
- Rich querying
- Stable storage format: Unstable
OpenSearchStore¶
OpenSearch search engine used as a key-value store. Collections are stored in separate indices with values in flattened fields.
from key_value.aio.stores.opensearch import OpenSearchStore
# Using URL and API key
store = OpenSearchStore(
url="https://localhost:9200",
api_key="your-api-key",
index_prefix="kv_store"
)
# With existing client
from opensearchpy import AsyncOpenSearch
client = AsyncOpenSearch(hosts=["https://localhost:9200"])
store = OpenSearchStore(
opensearch_client=client,
index_prefix="kv_store"
)
Installation:
Use Cases:
- Applications already using OpenSearch
- Need for search capabilities with AWS-managed service
- Analytics and logging
Characteristics:
- Search capabilities
- Distributed by default
- Collections stored in separate indices
- Values stored in flat_object fields
- Stable storage format: Unstable
Sanitization Strategies:
OpenSearch has specific restrictions on keys and index names. Use the built-in sanitization strategies to avoid issues:
from key_value.aio.stores.opensearch import (
OpenSearchStore,
OpenSearchV1KeySanitizationStrategy,
OpenSearchV1CollectionSanitizationStrategy,
)
store = OpenSearchStore(
url="https://localhost:9200",
index_prefix="kv_store",
key_sanitization_strategy=OpenSearchV1KeySanitizationStrategy(),
collection_sanitization_strategy=OpenSearchV1CollectionSanitizationStrategy(),
)
MongoDBStore¶
Document database used as a key-value store.
from key_value.aio.stores.mongodb import MongoDBStore
store = MongoDBStore(url="mongodb://localhost:27017/test")
Installation:
Use Cases:
- Applications already using MongoDB
- Document-oriented data
- Flexible schemas
Characteristics:
- Document storage
- Rich querying
- Horizontal scaling
- Stable storage format: Unstable
PostgreSQLStore¶
PostgreSQL database with JSONB storage for flexible key-value data.
Note: PostgreSQL is async-only. This store uses asyncpg which
provides native async/await operations.
from key_value.aio.stores.postgresql import PostgreSQLStore
# Using connection URL
store = PostgreSQLStore(url="postgresql://localhost:5432/mydb")
# Using connection parameters
store = PostgreSQLStore(
host="localhost",
port=5432,
database="mydb",
user="myuser",
password="mypass"
)
async with store:
await store.put(key="user_1", value={"name": "Alice"}, collection="users")
user = await store.get(key="user_1", collection="users")
Installation:
Use Cases:
- Applications already using PostgreSQL
- Need for SQL querying on stored data
- ACID transaction requirements
- Complex data relationships
Characteristics:
- JSONB storage for efficient querying
- TTL support via expiration timestamps
- Single table design (collections as column values)
- Async-only (uses asyncpg)
- Stable storage format: Unstable
MemcachedStore¶
High-performance distributed memory caching system.
from key_value.aio.stores.memcached import MemcachedStore
store = MemcachedStore(host="127.0.0.1", port=11211)
Installation:
Use Cases:
- Distributed caching
- Session storage
- High-throughput caching
Characteristics:
- Very fast
- Simple protocol
- Distributed by design
- No persistence
- Stable storage format: Unstable
Choosing a Store¶
Development¶
Recommended: MemoryStore or DiskStore
- Fast iteration
- No setup required
- Easy debugging
Production Caching¶
Recommended: RedisStore or ValkeyStore
- High performance
- Distributed
- Production-ready
- Stable storage format
# Production caching
from key_value.aio.stores.redis import RedisStore
store = RedisStore(url="redis://localhost:6379/0")
Long-Term Storage¶
Recommended: Stores with Stable stability rating
RedisStoreValkeyStoreDiskStoreMultiDiskStoreKeyringStore
Avoid unstable stores for data you can't afford to lose or migrate.
Sensitive Data¶
Recommended: KeyringStore or VaultStore
- OS-level encryption
- Secure by default
- Audit logging (Vault)
# Sensitive data
from key_value.aio.stores.keyring import KeyringStore
store = KeyringStore(service_name="my-app")
Serverless/Cloud¶
Recommended: DynamoDBStore (AWS)
- Fully managed
- Auto-scaling
- No servers to maintain
# AWS Lambda
from key_value.aio.stores.dynamodb import DynamoDBStore
store = DynamoDBStore(table_name="kv-store", region_name="us-east-1")
Store Compatibility¶
All stores implement the same protocol, making it easy to switch:
# Development
store = MemoryStore()
# Production
store = RedisStore(url="redis://localhost:6379/0")
# Your code works with both!
await store.put(key="user:123", value={"name": "Alice"}, collection="users")
See the API Reference for complete store documentation.