---
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 `