# Caching in Server Components

Data fetching in Rebask is handled by React Server Components, but we add additional features to cover some gaps:

- [`durableCache`](#durablecache): cache data across requests and builds.
- [`"use cache"`](#use-cache): cache the result of an async function across requests.
- [Fetch deduping](#fetching-in-server-components): identical safe `GET`/`HEAD` fetches within the same request are deduped automatically.
- [Cache Lifetimes](./cache-lifetimes.md): set revalidation windows and tags on cache entries.

By default, entries stay fresh for one hour and remain usable for one year. Use
[`cacheLife()`](./cache-lifetimes.md#cachelife) to change either value.

## Fetching in Server Components

You can fetch data directly in async Server Components:

```tsx
export default async function ProductsPage() {
  const res = await fetch("https://api.example.com/products")
  const products = await res.json()

  return <ProductList products={products} />
}
```

Go to the React docs to learn more about [async Server Components](https://react.dev/reference/rsc/server-components#async-components-with-server-components).

Identical safe `GET`/`HEAD` fetches in one request are
[deduped by default](../configuration.md#rebask-dedupefetch). Pass `signal` to opt out:

```tsx
const controller = new AbortController()
const res = await fetch("https://api.example.com/products", { signal: controller.signal })
```

A `signal` means the caller controls the request lifecycle, so deduping can interfere with cancellation.

## `durableCache`

Cache a JSON-serializable value returned by an async function across requests and builds. Unlike
`"use cache"`, entries are not scoped to a deployment ID, so a cache handler that persists entries
can reuse them across builds.

```ts
import { durableCache, cacheLife, cacheTag } from "@rebask/core/cache"

export const getProducts = durableCache(async (category: string) => {
  const res = await fetch(`https://api.example.com/products?cat=${category}`)
  const data = await res.json()
  cacheLife({ revalidate: 300, expire: 3600 })
  cacheTag("products", `products:${category}`)
  return data
})
```

Use the optional second argument to include values that affect the cache but aren't function arguments, such as environment variables:

```ts
export const getProducts = durableCache(
  async (category: string) => {
    const res = await fetch(`${process.env.API_URL}/products?cat=${category}`)
    return res.json()
  },
  [process.env.API_URL],
)
```

The cache key combines a hash of the function source, a SHA-256 hash of the serialized arguments,
and the serialized `deps`. Arguments and `deps` must be JSON-serializable: strings, finite numbers,
booleans, `null`, `undefined`, arrays, and plain objects. Non-serializable arguments, such as a
promise or a `Map`, throw when the function is called. Non-serializable `deps` throw when
`durableCache()` is created.

Persisting `durableCache` entries lets new builds reuse unchanged data, but also lets them serve
entries from earlier builds when keys stay unchanged. Changes to environment variables or the
returned data shape must therefore be reflected in the cache key or `deps` to avoid conflicts.

## `"use cache"`

Caches the result of an async function.

```ts
import { cacheLife, cacheTag } from "@rebask/core/cache"

export async function getProduct(id: string) {
  "use cache"
  cacheLife({ revalidate: 300, expire: 3600 })
  cacheTag("product", `product:${id}`)
  return db.products.find(id)
}
```

The generated cache key includes the [deployment id](../configuration.md#rebask-deploymentid),
module path, function name, and the encoded arguments. When the arguments encode to `FormData`, Rebask hashes it with SHA-256 first.

See [Server Cache Keys](./introduction.md#server-cache-keys) to learn why "use cache" entries include a deployment ID.

## Server component cache lifetimes and invalidation

[Page](./page-caching.md), [RSC](./rsc-caching.md), and Server Component cache entries share the same
lifetime, tag, and invalidation model. See [Cache Lifetimes](./cache-lifetimes.md) for the concepts
and APIs.

See [Cache Handler](./cache-handler.md) to configure a custom server cache storage implementation.
