ocache

Composable caching primitives with TTL, stale-while-revalidate, and HTTP response caching. Zero framework dependencies — works with any runtime that has standard Request/Response.
[!TIP]
📖 Head to the documentation to learn more.
Features
Usage
Caching Functions
Wrap any function with defineCachedFunction to add caching with TTL, stale-while-revalidate, and request deduplication:
import { defineCachedFunction } from "ocache";
const cachedFetch = defineCachedFunction(
async (url: string) => {
const res = await fetch(url);
return res.json();
},
{
maxAge: 60,
name: "api-fetch",
},
);
const data = await cachedFetch("https://api.example.com/data");
[!NOTE]
Learn more in the Caching Functions guide, and see Invalidation & Expiration and Storage.
Caching HTTP Handlers
Wrap HTTP handlers with defineCachedHandler for automatic response caching with etag, last-modified, and 304 Not Modified support:
import { defineCachedHandler } from "ocache";
const handler = defineCachedHandler(
async (event) => {
const url = event.url ?? new URL(event.req.url);
const data = await getExpensiveData(url.pathname);
return new Response(JSON.stringify(data), {
headers: { "content-type": "application/json" },
});
},
{
maxAge: 300,
swr: true,
staleMaxAge: 600,
varies: ["accept-language"],
allowQuery: ["color"],
},
);
[!NOTE]
Learn more in the Caching HTTP Handlers guide, and see Query Parameters, Cookies, Cache-Control & Eligibility, and Incremental Static Regeneration.
API
CachedEventHandler
type CachedEventHandler<E extends HTTPEvent = HTTPEvent> = EventHandler<E> &
Cached event handler returned by defineCachedHandler.
An EventHandler augmented with on-demand revalidation methods forwarded from
the underlying cached function. Each accepts the HTTPEvent directly and derives
the exact storage key the handler caches under, so no manual key reconstruction is needed.
cachedFunction
const cachedFunction = defineCachedFunction;
Alias for defineCachedFunction.
CacheStatus
type CacheStatus = "hit" | "stale" | "revalidated" | "miss";
How a cached value was served on a given call.
"hit" — a fresh cached value was returned without re-resolving.
"stale" — a stale value was served while a background SWR refresh runs.
"revalidated" — a prior value existed but was expired/invalid, so it was
re-resolved in the foreground (no stale value served) before returning.
"miss" — the value was resolved fresh on this call (nothing was cached).
createMemoryStorage
function createMemoryStorage(opts: MemoryStorageOptions =
Creates an in-memory storage backed by a Map with optional TTL support (in seconds) and LRU eviction.
defineCachedFunction
function defineCachedFunction<T, ArgsT extends unknown[] = any[]>(
fn: (...args: ArgsT) => T | Promise<T>,
opts: CacheOptions<T, ArgsT> =
Wraps a function with caching support including TTL, SWR, integrity checks, and request deduplication.
Parameters:
fn — The function to cache.
opts — Cache configuration options.
Returns: — A cached function with a .resolveKey(...args) method for cache key resolution.
defineCachedHandler
function defineCachedHandler<E extends HTTPEvent = HTTPEvent>(
handler: EventHandler<E>,
opts: CachedEventHandlerOptions<E> =
Wraps an HTTP event handler with response caching.
Automatically generates cache keys from the URL path and variable headers,
sets cache-control, etag, and last-modified headers, and handles
304 Not Modified responses via conditional request headers.
Parameters:
handler — The event handler to cache.
opts — Cache and HTTP-specific configuration options.
Returns: — A new event handler that serves cached responses when available. The handler
also exposes .resolveKeys(event), .invalidate(event), and .expire(event) for
on-demand revalidation, keyed exactly as the handler caches (no key reconstruction).
EventHandler
type EventHandler<E extends HTTPEvent = HTTPEvent> = (
Handler function that receives an HTTPEvent and returns a response value.
expireCache
async function expireCache<ArgsT extends unknown[] = any[]>(
input:
Expires cached entries for given arguments and cache options across all base prefixes,
without removing them.
Unlike invalidateCache (which removes entries entirely), expired entries keep
serving the stale value with SWR — still bounded by the originally configured
staleMaxAge window — while the next access triggers a background refresh.
Without SWR, the next call re-resolves before returning.
Uses the same key derivation as defineCachedFunction / resolveCacheKeys.
Pass the same maxAge / swr / staleMaxAge options you cache with so the
remaining storage TTL is preserved.
Parameters:
input — Object with options (cache options) and optional args (function arguments).
Example:
await expireCache({
options: { name: "fetchUser", getKey: (id: string) => id, maxAge: 60, staleMaxAge: 300 },
args: ["user-123"],
});
invalidateCache
async function invalidateCache<ArgsT extends unknown[] = any[]>(
input:
Invalidates (removes) cached entries for given arguments and cache options across all base prefixes.
Uses the same key derivation as defineCachedFunction / resolveCacheKeys.
Parameters:
input — Object with options (cache options) and optional args (function arguments).
Example:
await invalidateCache({
options: { name: "fetchUser", getKey: (id: string) => id },
args: ["user-123"],
});
resolveCacheKeys
async function resolveCacheKeys<ArgsT extends unknown[] = any[]>(
input:
Resolves all cache storage keys (one per base prefix) for given arguments and cache options.
Uses the same key derivation as defineCachedFunction internally:
- When
opts.getKey is provided, it is called with args to produce the key segment.
- Otherwise,
args are hashed with ohash (same default as defineCachedFunction).
Pass the same getKey, name, group, and base options you use in
defineCachedFunction / defineCachedHandler to get the exact storage keys.
Parameters:
input — Object with options (cache options) and optional args (function arguments).
Returns: — An array of storage key strings (one per base prefix).
Example:
const keys = await resolveCacheKeys({
options: { name: "fetchUser", getKey: (id: string) => id },
args: ["user-123"],
});
for (const key of keys) {
await useStorage().set(key, null);
}
setStorage
function setStorage(storage: StorageInterface): void;
Sets a custom storage implementation to be used by all cached functions.
useStorage
function useStorage(): StorageInterface;
Returns the current storage instance. If none has been set via setStorage, lazily initializes an in-memory storage.
Development
local development
- Clone this repository
- Install latest LTS version of Node.js
- Enable Corepack using
corepack enable
- Install dependencies using
pnpm install
- Run interactive tests using
pnpm dev
License
Published under the MIT license 💛.