litestar-stores
Stores
Use this skill when the problem is Litestar's interchangeable key-value store layer, not relational data modeling.
Execution Workflow
- Decide whether the feature really belongs in a Litestar store: cache, session, rate limit, or other ephemeral/shared key-value state.
- Choose the backend based on process model, durability, latency, and cleanup needs.
- Decide whether stores should be wired explicitly by name, created lazily through
StoreRegistry, or derived from a namespaced default factory. - Define key naming, namespacing boundaries, TTL policy, and any renewal-on-read behavior.
- Wire integrations such as response caching, sessions, or rate limiting to named stores intentionally.
- Plan cleanup and shutdown behavior, especially for
FileStoreexpiry cleanup and Redis client ownership. - Verify expiry, isolation, and multi-worker behavior before relying on the store in production.
Core Rules
- Treat stores as interchangeable key-value infrastructure, not as ad hoc object persistence.
- Design for the store contract: values are bytes-oriented, even when a backend has extra convenience behavior.
- Keep namespacing and store names intentional before using bulk operations like
delete_all(). - Match TTL policy to the feature: absolute expiry, renewal on access, or no expiry.
- Do not assume all backends clean up expired data the same way.
- Prefer named stores or namespaced stores over one flat keyspace shared by unrelated features.
- Use a distributed backend for any state that must survive across workers or instances.
- Make store ownership explicit when external clients or filesystem paths need lifecycle management.
Decision Guide
- Use
MemoryStorefor simple single-process caching or low-stakes ephemeral state with minimal overhead. - Use
FileStorewhen persistence on disk matters more than speed, especially for larger or longer-lived data. - Use
RedisStorefor general production-grade shared state, multi-worker communication, and namespaced bulk operations. - Use
ValkeyStorewhen you want Redis-style behavior on Valkey; Litestar documents it as equivalent in practice to Redis for these store concerns. - Use explicit
stores={...}mappings when integrations must resolve known store names. - Use
StoreRegistry(default_factory=...)when undefined store names should be created lazily from one policy. - Use
with_namespace()when one underlying backend should safely host multiple isolated logical stores. - Use
litestar-cachingalongside this skill when response-cache TTL, cache keys, or cache filtering are the main design problem.
Reference Files
Read only the sections you need:
- For store operations, bytes-vs-string behavior, TTL renewal, and cleanup mechanics, read references/store-operations-and-data.md.
- For backend selection tradeoffs and backend-specific operational notes, read references/backend-selection-and-lifecycle.md.
- For
StoreRegistry, namespacing, integration wiring, and default-factory patterns, read references/registry-and-namespacing.md.
Store Fundamentals
Litestar store operations center around a small async API:
set(key, value, expires_in=...)get(key, renew_for=...)delete(key)delete_all()exists(key)expires_in(key)
Key behavioral rules from the docs:
- Stores generally accept bytes and return bytes.
set()also accepts strings for convenience, butget()still returns bytes.expires_incan be set when writing data.renew_forcan be passed toget()to extend TTL on access when the backend supports expiry for that key.- If
delete()is called for a missing key, it is a no-op.
Backend Selection
MemoryStore
- Default Litestar store.
- Lowest overhead.
- No persistence.
- Not thread-safe or multiprocess-safe.
- Avoid for multi-worker or multi-instance shared state.
FileStore
- Persists data on disk.
- Slower than memory-backed approaches.
- Good fit when data volume, longevity, or backupability matters.
- Supports namespacing via sub-paths.
- Expired entries are not proactively removed; plan
delete_expired()calls.
RedisStore
- Suitable for almost all applications that need shared or durable-ish key-value infrastructure.
- Supports namespacing and safe namespace-scoped
delete_all(). - Native expiry behavior comes from Redis itself.
- Good fit for multi-worker deployments, sessions, rate limiting, and shared cache state.
ValkeyStore
- Same practical guidance as
RedisStoreaccording to the Litestar docs. - Supports namespacing.
- Use when the deployment standard is Valkey rather than Redis.
TTL and Expiry Semantics
- Use
expires_inonset()for absolute expiration. - Use
renew_foronget()for sliding expiration or access-based renewal, such as sessions or LRU-like behavior. - Redis/Valkey use native expiry mechanisms.
FileStoredeletes expired values only when they are accessed or whendelete_expired()is run explicitly.MemoryStoreandFileStoremay retain expired data until access or cleanup; do not treat TTL as equivalent to immediate background deletion on those backends.
Namespacing
- Namespacing exists to make shared backends safe for multiple logical purposes.
with_namespace()creates a child store whose operations affect only that namespace and its children.- This is especially important before using
delete_all(). RedisStoreusesLITESTARas the default namespace.- Passing
namespace=Nonedisables Redis namespacing and makesdelete_all()unavailable. - File-backed namespacing uses sub-paths under the parent store path.
Store Registry
Litestar.storesexposes the application'sStoreRegistry.- A registry can start from a mapping of store names to store instances.
app.stores.get(name)returns a registered store or creates one via the registry'sdefault_factory.- The default registry factory returns a new
MemoryStorefor unknown names. - You can pass a custom
StoreRegistryto change that behavior globally. StoreRegistry.register(name, store, allow_override=False)is the explicit registration path when dynamic creation is not enough.
Integration Wiring
Litestar integrations resolve stores by name through the registry. Important consequences:
- Response caching defaults to the
response_cachestore name unless configured otherwise. - Session middleware defaults to the
sessionsstore name unless configured otherwise. - Rate limiting resolves its store by name as well.
- These names are conventions, not magic constants; you can point integrations at other names with their own config.
- One registry can host multiple backends for different integrations, or one namespaced backend can serve many integrations through the default factory.
Data Contract and Serialization Boundary
- The portable store contract is bytes-based.
- Do not rely on backend-specific object behavior if the store may be swapped later.
MemoryStorecan technically hold arbitrary Python objects because it stores directly in memory, but Litestar's documented interface does not guarantee that portability.- Serialize structured values explicitly before storing when backend interchangeability matters.
Cleanup and Lifetime
- Call
delete_expired()periodically forMemoryStoreand especiallyFileStorewhen stale entries would otherwise accumulate. FileStore.delete_expired()is a good startup or maintenance task when the directory is long-lived.- If you create a
RedisStoredirectly around your own Redis client and do not use the helper lifecycle, you are responsible for shutting that client down. - Prefer
RedisStore.with_client(...)or explicit ownership flags when you want Litestar/the store to manage the client lifecycle.
Recommended Defaults
- Keep
MemoryStoreonly for local development, single-process apps, or low-stakes ephemeral state. - Prefer Redis or Valkey for shared cache, sessions, and rate limits in production.
- Use explicit store names for integrations when different backends serve different concerns.
- Use one root namespaced Redis/Valkey store when you want shared infrastructure with isolated logical children.
- Serialize structured data to bytes or strings intentionally rather than leaning on
MemoryStoreobject storage. - Run expiry cleanup on file-backed stores as a deliberate maintenance task.
Example Pattern
from litestar import Litestar, get
from litestar.config.response_cache import ResponseCacheConfig
from litestar.middleware.rate_limit import RateLimitConfig
from litestar.middleware.session.server_side import ServerSideSessionConfig
from litestar.stores.redis import RedisStore
from litestar.stores.registry import StoreRegistry
root_store = RedisStore.with_client()
@get("/cached", cache=True, sync_to_thread=False)
def cached_handler() -> str:
return "hello"
app = Litestar(
[cached_handler],
stores=StoreRegistry(default_factory=root_store.with_namespace),
response_cache_config=ResponseCacheConfig(store="response_cache"),
middleware=[
ServerSideSessionConfig(store="sessions").middleware,
RateLimitConfig(rate_limit=("second", 10), store="rate_limit").middleware,
],
)
Anti-Patterns
- Using
MemoryStorefor state that must be shared across workers or processes. - Treating stores as a substitute for relational or queryable persistence.
- Storing arbitrary Python objects because
MemoryStorehappens to allow it. - Using one flat keyspace and then calling
delete_all()without namespaces or isolated store names. - Assuming expired entries disappear immediately on
FileStoreorMemoryStore. - Forgetting to clean up filesystem-backed expired entries.
- Passing
namespace=Noneto Redis and then expecting safe namespace-scoped bulk deletion. - Assuming integration store names are fixed and unchangeable instead of config-driven.
- Adding Memcached as if it were a supported drop-in backend.
Validation Checklist
- Confirm the selected backend matches process topology and durability requirements.
- Confirm values are serialized in a backend-portable way when portability matters.
- Confirm TTL behavior matches actual backend semantics, including renewal-on-read where used.
- Confirm file- or memory-backed stores have an explicit expired-entry cleanup strategy when needed.
- Confirm namespacing or store naming prevents cross-feature collisions and unsafe bulk deletion.
- Confirm
app.stores.get(name)resolves the intended store for each integration. - Confirm cache, sessions, and rate limiting are pointed at the intended store names.
- Confirm Redis/Valkey client shutdown ownership is explicit.
- Confirm multi-worker deployments do not depend on
MemoryStore.
Cross-Skill Handoffs
- Use
litestar-cachingfor response-cache TTL, key-builder, and cache-filter strategy. - Use
litestar-authenticationorlitestar-securitywhen session/auth data is the main concern. - Use
litestar-middlewarewhen rate limit or session middleware behavior is the primary task. - Use
litestar-app-setupfor startup/shutdown cleanup hooks around store maintenance. - Use
litestar-testingto verify expiry, integration wiring, and multi-backend behavior.
Litestar References
- https://docs.litestar.dev/latest/usage/stores.html
- https://docs.litestar.dev/latest/usage/caching.html
- https://docs.litestar.dev/latest/reference/stores/base.html
- https://docs.litestar.dev/latest/reference/stores/memory.html
- https://docs.litestar.dev/latest/reference/stores/registry.html
- https://docs.litestar.dev/latest/reference/stores/file.html
- https://docs.litestar.dev/latest/reference/stores/redis.html
- https://docs.litestar.dev/latest/reference/stores/valkey.html
More from alti3/litestar-skills
litestar-responses
Build Litestar responses with typed return values, explicit Response containers, layered response classes, headers, cookies, status-code control, redirects, files, streams, server-sent events, ASGI app returns, and background tasks. Use when shaping outbound HTTP behavior, correcting response contracts, or choosing the right Litestar response primitive. Do not use for request parsing, validation, or authentication policy design.
22litestar-logging
Configure Litestar logging with `LoggingConfig`, `queue_listener`, exception logging policy, selective stack-trace suppression, standard logging, picologging, Structlog, and custom logging config subclasses. Use when establishing or refactoring application logging behavior, request-level logs, or production-safe error logging in Litestar. Do not use for metrics/tracing instrumentation or exception-response contract design.
22litestar-authentication
Implement Litestar authentication with custom authentication middleware, built-in security backends, JWT and session flows, route inclusion and exclusion rules, and typed auth context on `Request` / `ASGIConnection`. Use when establishing identity, issuing or validating credentials, or attaching authenticated user context in Litestar. Do not use for generic request parsing, broad security audits, or unrelated transport concerns.
22litestar-middleware
Design and apply Litestar middleware for cross-cutting concerns such as CORS, CSRF, allowed-host checks, compression, rate limiting, logging, sessions, request enrichment, policy enforcement, and custom ASGI pipeline control. Use when behavior must wrap broad route sets consistently across the ASGI stack. Do not use for route-specific business rules, simple response mutation better handled by lifecycle hooks, or auth/guard policy work that belongs in security-focused skills.
20litestar-routing
Design and implement Litestar routing with app/router/controller composition, handler decorators, path and parameter modeling, route indexing/reverse lookups, ASGI mounting, and layered route metadata. Use when creating or refactoring endpoint topology and URL contracts. Do not use for purely internal service logic unrelated to HTTP route structure.
18litestar-dto
Configure Litestar DTO behavior for inbound parsing and outbound serialization, including layer-scoped `dto`/`return_dto`, `DTOConfig` policies, `DTOData` update workflows, and custom `AbstractDTO` implementations. Use when API payload contracts differ from internal model structures. Do not use when internal models can be exposed safely without transformation.
18