Overview

Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation.

Voltro ships a first-class cache in @voltro/cache. It is always on — the in-process memory backend is the zero-config default, so ctx.cache works in every handler from the first boot with nothing to install. You opt into a distributed backend (Redis & friends) only when you need cross-instance sharing.

There are two ways to use it, and they share one backend:

  1. Low-levelctx.cache.wrap(key, { ttl, tags }, () => compute()) in any handler. Cache-aside with tags, stale-while-revalidate, and single-flight de-duplication. Use it for expensive derived work: aggregations, external-API enrichment, rendered fragments.
  2. Automatic query caching — add a cache field to a defineQuery and the framework caches the server snapshot and invalidates it automatically when a mutation writes any table the query depends on. Zero manual busting.

The defining idea mirrors the rest of Voltro: the backend is a configuration choice, the code is identical. The same wrap call and the same cache: field run against the in-process map in dev and against Redis (or Valkey / KeyDB / Dragonfly / Upstash) in production — you flip CACHE_BACKEND, not your handlers.

// app.config.ts — memory (default) or redis
export default { type: 'api', name: 'myApi', store: 'postgres', cache: 'redis' }
// any handler — works on every backend
export default async (input: { orgId: string }, ctx) =>
  ctx.cache.wrap(
    `dashboard:${input.orgId}`,
    { ttlMs: 60_000, tags: [`org:${input.orgId}`] },
    async () => expensiveDashboard(ctx, input.orgId),
  )

What it is not

  • Not the reactive query engine. Live useSubscription queries already stay fresh by pushing deltas — caching is for non-live derived work and for sharing a query's initial snapshot across many subscribers/instances.
  • Not a runtime plugin. A cache backend is infrastructure, so it's an app.config + baseline concern (voltro add redis), not a plugins: entry.

Where to go next

  • Backends & engines — memory vs Redis, the five RESP-compatible engines, connection presets, env vars.
  • Low-level wrapctx.cache / the Effect Cache service, tags, SWR, single-flight.
  • Query caching — the cache: field, the scope security rule, auto-invalidation.
  • Durable key-valuectx.kv (durable, never evicted — for state you can't recompute): the full API, TTL, tenant namespacing.
  • Key-value backendsdatabase (durable) vs redis vs memory, the KV_BACKEND selector, the KvStore port, custom backends.
  • Named connections — the shared registry behind the cache / KV / rate limiter / broadcast, the <NAME>_REDIS_URLREDIS_URL scheme, and per-concern enablement.
  • Enabling Redisvoltro add redis, create-project --cache=redis, the voltro cache CLI, the dashboard panel.