Backends & engines
The two cache backends (memory + RESP) and the five Redis-compatible engines they cover — Redis, Valkey, KeyDB, Dragonfly, Upstash — plus every env var and connection preset.
The backend is chosen by environment variable (or app.config.ts) and is shared by both caching modes. Everything else — wrap, the cache: query field, tag invalidation — is backend-agnostic.
Selecting a backend
CACHE_BACKEND memory | redis (default: memory)
CACHE_REDIS_URL redis/rediss/REST url (falls back to REDIS_URL)
CACHE_REDIS_DRIVER resp | http (default: resp; http = Upstash REST, for edge)
CACHE_REDIS_TOKEN http-driver auth (falls back to UPSTASH_REDIS_REST_TOKEN)
CACHE_KEY_PREFIX namespace (redis backend only; default: voltro:cache)
CACHE_MAX_ENTRIES memory capacity cap (optional, memory backend only)CACHE_KEY_PREFIX is consumed only by the redis backend (it namespaces the RESP keyspace). Under CACHE_BACKEND=memory it parses but is a no-op — the memory map isn't a shared keyspace, so there is nothing to prefix.
// app.config.ts — env always wins over this
export default { type: 'api', name: 'myApi', store: 'postgres', cache: 'redis' }The resolved backend is printed at boot — voltro logs --tail 50 | grep 'cache backend':
[voltro:dev] cache backend resolved: redis (driver resp)memory (default)
In-process Map with lazy expiry. Single instance only — entries live in the process, invisible to other nodes. Zero-config, perfect for dev and single-pod deployments. CACHE_MAX_ENTRIES bounds it for write-heavy workloads. Resets on restart.
Capacity eviction is oldest-by-insertion (FIFO) — reads do not bump recency, so under cap pressure a hot frequently-read entry is dropped before a cold never-read one. This is NOT LRU: it's a deliberate simplicity trade for a single-process dev/cache tier (the cross-instance tier is redis). Size the cap above your hot-set, or rely on per-entry TTL, if that matters.
Use it when: you're in dev, or you run exactly one app instance and don't need the cache to survive a restart.
redis — one backend, five engines
The redis backend speaks the RESP wire protocol, so a single implementation drives five engines with no per-engine code:
| Engine | Driver | Notes |
|---|---|---|
| Redis | resp (TCP) |
The reference implementation. |
| Valkey | resp (TCP) |
The Linux-Foundation fork of Redis — drop-in. |
| KeyDB | resp (TCP) |
Multithreaded Redis fork — drop-in. |
| Dragonfly | resp (TCP) |
Modern high-throughput drop-in. |
| Upstash | resp (TCP) or http (REST) |
Use http for serverless/edge runtimes where a persistent TCP socket isn't viable. |
Connection presets:
# Redis / Valkey / KeyDB / Dragonfly (all identical — just point at the server)
CACHE_BACKEND=redis CACHE_REDIS_URL=redis://localhost:6379
# TLS
CACHE_REDIS_URL=rediss://default:password@host:6379
# Upstash over the edge HTTP/REST API
CACHE_BACKEND=redis \
CACHE_REDIS_DRIVER=http \
CACHE_REDIS_URL=https://your-db.upstash.io \
CACHE_REDIS_TOKEN=********Use it when: you run more than one app instance (k8s replicas, multi-PM2, ECS tasks) and need a shared cache, or you want the cache to survive restarts.
Storage layout
Under CACHE_KEY_PREFIX (default voltro:cache):
- value keys →
voltro:cache:v:<key>(TTL viaPSETEX; JSON-encoded) - tag sets →
voltro:cache:t:<tag>(a Redis SET of the raw keys carrying that tag)
clear() is scoped to the prefix via SCAN — it never runs FLUSHDB, so a Redis shared with other framework state (e.g. the read-replica RYW store) is safe.
Reference semantics differ by backend. The memory backend returns the same object reference you stored (fast, but mutating a cached object mutates the cache — don't). The Redis backends JSON round-trip, so they always return a fresh copy. Treat cached values as immutable on both.
Choosing
- One instance / dev →
memory. Nothing to run. - Multiple instances, or restart-survival →
redis(pick any of the five engines by URL). - Serverless / edge (no persistent TCP) →
rediswithCACHE_REDIS_DRIVER=http(Upstash).
To provision the infra (a Redis container in compose / a Deployment in helm) plus the env, see Enabling Redis — voltro add redis wires it all.