# Vercel

Deploy Rebask to Vercel with the Build Output API.

## Install the Vercel adapter

::package-manager

```bash [pnpm]
pnpm add -D @rebask/vercel
```

```bash [npm]
npm install -D @rebask/vercel
```

```bash [bun]
bun add -d @rebask/vercel
```

```bash [yarn]
yarn add -D @rebask/vercel
```

::

Add `vercelAdapter()` to your Vite plugins:

```ts
// vite.config.ts
import { vercelAdapter } from "@rebask/vercel"

plugins: [rsc(), react(), rebask(), vercelAdapter()]
```

The adapter only runs during a Vercel build, when `VERCEL` is set.

Configure the adapter:

```ts
vercelAdapter({
  runtime: "nodejs24.x",
  memory: 1024,
  maxDuration: 60,
  regions: ["iad1"],
})
```

| Option             | Type                | Default                        | Description                                                                                        |
| ------------------ | ------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------- |
| `runtime`          | `nodejs${number}.x` | `nodejs24.x`                   | Node.js runtime for both generated functions.                                                      |
| `memory`           | `number`            | Platform default               | Memory in MB.                                                                                      |
| `maxDuration`      | `number`            | Platform default               | Maximum execution time in seconds.                                                                 |
| `regions`          | `string[]`          | Platform default               | Function regions.                                                                                  |
| `images`           | `ImagesConfig`      | Auto-detected, otherwise unset | Vercel image optimization. See [Images](#images).                                                  |
| `disablePrerender` | `boolean`           | `false`                        | Skip prerender packaging and PPR. Requires a custom [`cacheHandler`](../caching/cache-handler.md). |

Function settings apply to both the server and proxy functions.

Build for Vercel:

```bash
VERCEL=1 vite build
```

Vercel sets `VERCEL` automatically. Use `VERCEL=1` for a local adapter build.

Writes `.vercel/output` (Build Output API). Deploy with the Vercel dashboard, Git integration, or:

```bash
vercel deploy --prebuilt
```

## Local testing

Test with the Vercel CLI:

```bash
vercel dev
```

`vercel dev` may rebuild the app. For a prebuilt deployment, run `vercel build` and then `vercel deploy --prebuilt`.

## What the adapter packages

On a Vercel build the adapter turns the Rebask production output into:

- A serverless function for HTML, RSC, resume, actions, and [route handlers](../routing/route-handlers.md)
- A proxy function when [`proxy.ts`](../routing/proxy.md) matches routes
- Static assets under `.vercel/output/static`
- **Prerender entries** for [PPR routes](../rendering/ppr.md): shared shells, layout intermediate shells (from layout [`prerenderParams`](../routing/introduction.md#prerenderparams)), and static paths
- Routing so the CDN can serve a shell and chain a **resume** request into the function

Shared dynamic routes use `allowQuery` for **every** dynamic segment (including the leaf). That way a full page upgrade for one param value cannot be reused for another (cache poison).

Known intermediate shells are separate, more specific prerender routes produced only at **build** time. Runtime never invents new intermediate keys.

## Request flow (PPR HTML)

1. **User GET** — CDN matches a prerender route and serves the static shell (`x-vercel-cache: PRERENDER` or `HIT` after warm).
2. **Resume POST** — platform chains into the function with `x-rebask-resume` to fill Suspense holes for this request.
3. **Background upgrade** — after resume finishes, the adapter schedules a revalidate (`x-prerender-revalidate`). Rebask renders a **full page** and Vercel writes it into that prerender slot for the current `allowQuery` values.

Later GETs for the same variation can be a full document (`x-vercel-cache: HIT`) with no shell stream.

| Matched entry                      | First paint           | Upgrade writes                 |
| ---------------------------------- | --------------------- | ------------------------------ |
| Shared shell (unknown param combo) | Shared fallback       | Full page for that param set   |
| Intermediate (build list)          | Intermediate fallback | Full page for remaining params |
| Already upgraded variation         | Full page             | Refresh full page when stale   |

Stale shared or intermediate entries are refreshed by the platform (ISR / SWR). Upgrade always targets a **full page**, not a new intermediate shell.

## Request flow (RSC payloads)

Each page and layout payload has a prerender entry for the full payload, and one for its shell. A static page that read no request data at build time has no separate shell, since its shell is the full payload. A shell never holds request data, so Vercel stores it as is. A tail always goes to the function.

Vercel stores whatever a prerender invocation returns, even a `no-store` response, so the full payload entry starts empty and chains every request into the function:

1. **User GET** — the CDN serves the empty entry and chains the request into the function, which renders the payload for this visitor.
2. **Background fill** — if that payload read no request data, the adapter has Vercel store it, and later GETs are a `HIT`.

## How this differs from Node / `vite preview`

|                                                            | Node (default cache)                                          | Vercel                                                     |
| ---------------------------------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------- |
| Where page HTML/RSC live                                   | Rebask `html:` / `rsc:` keys (memory or `cacheHandler`)       | Vercel prerender CDN entries                               |
| Shared shell                                               | One key per route file                                        | One prerender pattern + `allowQuery`                       |
| Intermediate shells                                        | Build list; can refill known keys at runtime if missing/stale | Build routes and fallbacks only                            |
| Unknown combo                                              | Shared → promote toward full pathname in Rebask cache         | Shared → full page in that `allowQuery` slot               |
| Resume                                                     | App streams shell + dynamic in one response                   | CDN shell, then resume POST to the function                |
| [`"use cache"`](../caching/server-components.md#use-cache) | Your `cacheHandler` or default                                | Your `cacheHandler` if set; otherwise Vercel Runtime Cache |

HTML and RSC page bodies are **not** written through a custom
[`cacheHandler`](../caching/cache-handler.md) on Vercel. Use `cacheHandler` for
[`"use cache"`](../caching/server-components.md#use-cache) data only (for example Redis). Omit it to
use Vercel’s runtime cache for `"use cache"`.

Page responses on Vercel do not include `x-rebask-cache` but `x-vercel-cache`. With `disablePrerender`, the custom `cacheHandler` owns page caching and `x-rebask-cache` remains available.

See also [Partial Pre-Rendering](../rendering/ppr.md) and
[intermediate shells](../caching/page-caching.md#page-cache-layers-intermediate-shells).

## Images

Image optimization can use Vercel’s `/_vercel/image` API instead of running the image handler in
the serverless function:

- If [`rebaskImage()`](../images.md) is configured, the adapter uses that configuration automatically.
- If both `rebaskImage()` and the adapter `images` option are set, `rebaskImage()` wins and the adapter warns.
- If only `images` is set, the adapter uses it.
- If neither is set, requests use the default [`rebask.image.ts`](../images.md#image-plugin-setup) handler, which may bundle Sharp.

The `images` option accepts Vercel’s image configuration, including `sizes`, `formats`, `minimumCacheTTL`, `domains`, `remotePatterns`, and `localPatterns`.

When image optimization is configured, `/_rebask/image` routes to `/_vercel/image`. See
[Images](../images.md) for the Rebask image configuration.

## `disablePrerender`

Set `disablePrerender: true` only when you supply a custom
[`cacheHandler`](../caching/cache-handler.md) and want to own page caching yourself. The adapter then skips prerender packaging and PPR wiring. The build fails if no
custom `cacheHandler` is configured.
