--- title: 'Request cache' slug: request-cache description: 'Memoize server-side work for the duration of a single request with requestCache and requestMemo.' --- ## Request cache The request cache memoizes work for the duration of one HTTP request. Entries die with the request, so a page that renders the same lookup in ten components pays for it once, and the next request always sees fresh data. ```ts import { requestCache } from 'mochi-framework'; const user = await requestCache(`user:${id}`, () => db.user(id)); ``` Every value the callback reads must appear in the key — the cache never inspects the function, so a key that omits `id` collides silently. ### requestMemo Wrap a function once at module scope and every call site is memoized by its arguments: ```ts import { requestMemo } from 'mochi-framework'; export const getUser = requestMemo((id: string) => db.user(id)); ``` ```svelte ``` The wrapper _is_ the shared identity: two separate `requestMemo()` calls over the same function get separate entries. Export the wrapped function so every importer shares it, or pass `{ namespace }` to deliberately share entries between wrappers. Arguments are keyed by a type-tagged serialization (`1` and `'1'` never collide; objects go through `JSON.stringify`). For arguments that can't be serialized — functions, class instances, cyclic objects — pass your own `key`: ```ts const getProfile = requestMemo((user: User) => db.profile(user.id), { key: (user) => user.id }); ``` ### Async Both forms store the in-flight promise on the first call, so concurrent callers share one execution rather than racing: ```ts // One fetch, three awaits. const [a, b, c] = await Promise.all([getUser('42'), getUser('42'), getUser('42')]); ``` A rejected promise evicts its entry, so a failure is never cached — the next call retries. ### The store `getRequestCache()` returns the underlying store when you need imperative access: ```ts import { getRequestCache } from 'mochi-framework'; const cache = getRequestCache(); cache.set('tenant', tenant); cache.get('tenant'); cache.delete('tenant'); cache.stats(); // { hits, misses } — also shown in the debug bar's Cache panel ``` ### Outside a request Called outside a request handler — a startup script, a background job, a detached email render — the callback simply runs uncached, with a one-time warning in development. Nothing throws, so helpers built on the request cache stay usable everywhere. For a `requestMemo` wrapper that is _expected_ to run outside a request — a background warm, a detached render, work reachable from a non-request endpoint — pass `{ quiet: true }` to suppress that warning, since falling through uncached there is intended rather than a mistake: ```ts export const getUser = requestMemo((id: string) => db.user(id), { quiet: true }); ``` ### On the client These are server-only helpers — they memoize against the request context, which only exists on the server. When an island's `