HydraCache
HydraCache is a Rust-native local async cache that is designed to grow toward database result caching and distributed synchronization later.
Status
HydraCache is in early development. The current implementation targets the first local-cache release.
Why HydraCache?
HydraCache is not trying to replace low-level cache engines, databases, or query processors. It is an application-facing cache layer for Rust services.
Compared with using Moka directly, HydraCache adds a smaller product-shaped API: loader helpers, TTLs, tag invalidation, local single-flight, codec-backed storage, and lightweight stats in one place.
Compared with ORM-level caches, HydraCache keeps freshness explicit. Keys, tags, and invalidation are application-controlled instead of hidden behind a large persistence framework.
Compared with Redis-style caches, HydraCache is embedded and local-first. The first version needs no server, proxy, daemon, or network hop.
Compared with ReadySet or Noria-style query engines, HydraCache deliberately does not try to incrementally maintain SQL result graphs. It is a lightweight cache library first, with database-result caching planned as an adapter layer.
The long-term direction is:
simple local cache -> database result-cache adapter -> optional distributed synchronization
v0 Scope
The first version includes:
- local async cache runtime
HydraCache::local()buildergetputget_or_loadget_or_insert_withtry_get_or_insert_withTypedCache<T>namespaced typed view- local single-flight miss deduplication
contains_key- per-entry TTL and default TTL
- tag-aware invalidation
- key invalidation
removeas a local-cache alias for key invalidationflushpostcardcodec overBytes- lightweight stats
- single-flight join stats
- tag-generation invalidation safety
- Moka-backed local storage
Out of scope for v0:
- SQLx adapter
- proc macros
- distributed invalidation
- cluster roles
- generation counters
- persistence
Example
use Duration;
use ;
use ;
async
# async
API Notes
get returns Ok(None) when the key is missing or expired.
get_or_load runs the loader on a miss and stores the loaded value with the provided CacheOptions.
get_or_insert_with is the short local-cache spelling for infallible async loaders.
try_get_or_insert_with is the fallible-loader spelling. It behaves the same as get_or_load.
typed::<T>("namespace") creates a typed, namespaced view over the same cache. It
keeps the shared storage, stats, single-flight, tags, and invalidation safety,
but removes repeated type annotations at call sites and prefixes keys as
namespace:key.
Concurrent get_or_load calls for the same missing key share one loader execution. Cache hits bypass single-flight entirely.
If a tag is invalidated while a tagged loader is still running, HydraCache skips storing that stale loader result. Callers after the invalidation start or join a fresh in-flight load instead of joining the stale one.
contains_key checks whether a key currently maps to a usable value. Expired entries are removed and reported as absent.
remove and invalidate_key both remove one key. remove is the shorter local-cache spelling; invalidate_key is kept for consistency with tag invalidation.
invalidate_tag removes all entries currently associated with the tag.
Use CacheOptions::tag("users") for one tag and CacheOptions::tags(["users", "user:42"]) for multiple tags.
stats returns lightweight counters for hits, misses, loads, single-flight joins, stale load discards, invalidations, and evictions. v0 does not wire backend eviction listeners yet, so evictions remains zero.
Release Plan
The v0 release plan is maintained here:
Workspace
crates/hydracache-core- core public types, codec, options, errors, statscrates/hydracache- user-facing local cache runtimecrates/hydracache-macros- future macro ergonomicscrates/hydracache-sqlx- future SQLx-first adapter layer