
# Getting Started

ocache is a set of composable caching primitives with **zero runtime dependencies**. It runs anywhere the standard `Request` and `Response` APIs exist: Node.js, Bun, Deno, Cloudflare Workers, and other edge runtimes.

It exposes two building blocks:

- [`defineCachedFunction`](/docs/functions) — wraps any async function with TTL caching, stale-while-revalidate, integrity checks, and deduplication of concurrent calls.
- [`defineCachedHandler`](/docs/handler) — wraps an HTTP handler with full response caching: `etag`, `304 Not Modified`, `Cache-Control`, `Vary`, and safe request narrowing.

## Installation

:pm-install{name="ocache"}

## Cache a function

```ts
import { defineCachedFunction } from "ocache";

const cachedFetch = defineCachedFunction(
  async (url: string) => {
    const res = await fetch(url);
    return res.json();
  },
  {
    name: "api-fetch",
    maxAge: 60, // fresh for 60 seconds
  },
);

// First call runs the function; calls within the next 60s return the cached result.
const data = await cachedFetch("https://api.example.com/data");
```

## Cache an HTTP handler

```ts
import { defineCachedHandler } from "ocache";

const handler = defineCachedHandler(
  async (event) => {
    const url = event.url ?? new URL(event.req.url);
    return Response.json(await loadData(url.pathname));
  },
  {
    maxAge: 300, // fresh for 5 minutes
    swr: true, // then serve stale while refreshing in the background
  },
);

// The event shape is { req: Request, url?: URL } — no framework required.
const res = await handler({ req: new Request("https://example.com/data") });
```

## Three things to know up front

1. **All durations are in seconds.** `maxAge`, `staleMaxAge`, `maxResolveTime`, and storage TTLs all use seconds, never milliseconds.
2. **`maxAge` defaults to 1 second.** Set it explicitly for anything you actually want cached.
3. **Storage is per instance.** Each cached function and handler gets its own in-memory store by default. Nothing is global, so unrelated caches can never collide. Pass the same [`storage`](/docs/storage) to share a backend — Redis, filesystem, or anything with `get`/`set`.

## Benchmarks

<div style="overflow-x:auto">
  <img src="/bench.svg" alt="ocache under load: p99 latency with and without cache, and origin-call reduction, for seven workloads" width="800" style="max-width:none">
</div>

Seven realistic workloads under load, each run twice — once with ocache in the path and once without, from the same seed, so the only difference between the two marks on a row is the cache. Storage latency is simulated from real backend figures rather than set to zero, and the cost of a hit is measured rather than assumed. [The benchmarks page](/docs/benchmarks) has the method, every storage backend, and every number.

## Where to go next

| Guide                                              | What it covers                                                            |
| -------------------------------------------------- | ------------------------------------------------------------------------- |
| [Caching Functions](/docs/functions)               | Options, cache keys, dynamic TTL, deduplication, custom serialization     |
| [Storage](/docs/storage)                           | The `StorageInterface`, custom backends, memory limits, multi-tier caches |
| [Invalidation & Expiration](/docs/invalidation)    | Purging entries, SWR-friendly expiry, standalone helpers                  |
| [Caching HTTP Handlers](/docs/handler)             | Response caching, conditional requests, request narrowing                 |
| [Query Parameters](/docs/query-params)             | Which query params vary the cache                                         |
| [Cookies](/docs/cookies)                           | The secure cookie default and how to opt back in                          |
| [Cache-Control & Eligibility](/docs/cache-control) | What is stored, what is advertised, response-side opt-outs                |
| [Incremental Static Regeneration](/docs/isr)       | Serve stale instantly, regenerate in the background                       |
| [API Reference](/docs/api)                         | Generated reference for every export                                      |
