rgoussu@goussu: ~/library/rust/storage
~/library/rust/storage cat redis.md

Redis from Rust — redis-rs & fred

# The redis crate as the default client and fred as the batteries-included alternative — connection management, typed command conversions, pub/sub and streams, and the cache/lock patterns.

Conceptsaved 2026-08-09 #rust#storage#redis#caching

Overview

Two clients cover Redis (and Valkey) from Rust. redis-rs (the redis crate) is the long-standing default: sync and async APIs, a typed command layer over a generic ToRedisArgs/FromRedisValue conversion system, cluster and sentinel support, and a ConnectionManager for auto-reconnection. fred is the batteries-included alternative built async-first: richer pooling, RESP3, client-side caching (invalidation tracking), automatic pipelining and reconnect policies as configuration rather than code. The patterns built on them — cache-aside, locks, rate limits, queues — transfer verbatim from Go and Java.

Key points

  • redis-rs basics: Client::open(url)get_multiplexed_async_connection(); commands as typed methods (con.set_ex("k", v, 60)) or the generic redis::cmd("SETEX") escape hatch; the FromRedisValue derive/impl system maps replies onto your types.
  • ConnectionManager (or a deadpool-redis pool) is the production form — multiplexed connections reconnect under the hood; bare connections don't.
  • fred's pitch: RedisPool with configurable reconnection/backoff, RESP3 by default, tracing integration, cluster-aware pipelining, client-side caching — the operational features you'd otherwise hand-roll; the trade is a bigger API surface and its own idioms.
  • Pub/sub: a dedicated connection in both clients (get_async_pubsub / fred's subscriber client) feeding a Stream of messages — pair with a broadcast channel to fan out in-process, the same shape as the WebSocket patterns.
  • Streams over lists for real queues — consumer groups, acks, XAUTOCLAIM recovery; both clients expose the X* family typed.
  • Lua/atomicity: redis::Script wraps EVALSHA with automatic loading — the check-and-set building block for locks and rate limiters; single-instance Redlock caveats apply unchanged.
  • Serialization is explicit: store serde_json/rmp-serde bytes and convert at the boundary — no automatic object mapping layer exists, matching the ecosystem's no-magic posture.

Examples

let client = redis::Client::open("redis://127.0.0.1/")?;
let mut con = client.get_multiplexed_async_connection().await?;

// cache-aside with TTL
let key = format!("user:{id}");
if let Some(bytes) = con.get::<_, Option<Vec<u8>>>(&key).await? {
    return Ok(serde_json::from_slice(&bytes)?);
}
let user = load_from_db(id).await?;
let _: () = con.set_ex(&key, serde_json::to_vec(&user)?, 300).await?;

Related