Skip to content

Caching

Most real programs repeat work: the same user is fetched twice, the same configuration is parsed on every request, the same database connection is opened by a dozen fibers at once. Effect’s caching modules let you compute a value once and reuse it — safely under concurrency, with control over lifetime, capacity, and resource cleanup.

There are two families of tools here, and they solve different problems:

  • Memoizing values — store the result of a lookup effect keyed by input. Concurrent misses for the same key share a single in-flight computation, and both successes and failures are cached. This is Cache (and ScopedCache when the cached values own resources).
  • Sharing resources — store a live resource (a connection, client, or session) and track how many fibers are using it, releasing it automatically when the last borrower lets go. This is RcMap and RcRef.

A third tool, Resource, sits in between: it keeps a single value loaded in memory and lets you refresh it on demand or on a schedule.

You want to…Use
Cache lookups by key, deduplicate concurrent misses, cap size with a TTLCache
Cache lookups whose values acquire scoped resourcesScopedCache
Memoize a single effect (no key)Effect.cached — see Cache
Share one scoped resource across many fibers, ref-countedRcRef
Share scoped resources by key, ref-countedRcMap
Keep a value loaded and refresh it manually or on a scheduleResource

The simplest cache is keyed by an input and backed by a lookup effect. Concurrent requests for the same key only run the lookup once.

import { Cache, Effect } from "effect"
const program = Effect.gen(function*() {
// A cache mapping user ids to (here, trivially computed) names.
// The lookup runs at most once per key until the entry is evicted.
const cache = yield* Cache.make({
capacity: 1000,
lookup: (id: number) => Effect.succeed(`user-${id}`)
})
const a = yield* Cache.get(cache, 1) // miss: runs the lookup
const b = yield* Cache.get(cache, 1) // hit: returns the cached value
return [a, b]
})
  • Cache and ScopedCache — memoize lookups by key, with capacity limits, fixed or dynamic TTLs, and scoped-resource variants. Also covers the no-key Effect.cached helpers.
  • Reference countingRcMap and RcRef share scoped resources and release them when the last reference goes away.
  • Resource — keep a single value loaded and refresh it manually or automatically with a Schedule.

Caching builds on a few concepts covered elsewhere: lookup functions are ordinary Effects, TTLs use Duration, scoped resources rely on scopes, and automatic refresh uses Schedule.