On this page

Vercel

Deploy Rebask to Vercel with the Build Output API.

Install the Vercel adapter

pnpm add -D @rebask/vercel

Add vercelAdapter() to your Vite plugins:

// 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:

vercelAdapter({
  runtime: "nodejs24.x",
  memory: 1024,
  maxDuration: 60,
  regions: ["iad1"],
})
OptionTypeDefaultDescription
runtimenodejs${number}.xnodejs24.xNode.js runtime for both generated functions.
memorynumberPlatform defaultMemory in MB.
maxDurationnumberPlatform defaultMaximum execution time in seconds.
regionsstring[]Platform defaultFunction regions.
imagesImagesConfigAuto-detected, otherwise unsetVercel image optimization. See Images.
disablePrerenderbooleanfalseSkip prerender packaging and PPR. Requires a custom cacheHandler.

Function settings apply to both the server and proxy functions.

Build for Vercel:

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:

vercel deploy --prebuilt

Local testing

Test with the Vercel CLI:

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
  • A proxy function when proxy.ts matches routes
  • Static assets under .vercel/output/static
  • Prerender entries for PPR routes: shared shells, layout intermediate shells (from layout 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 entryFirst paintUpgrade writes
Shared shell (unknown param combo)Shared fallbackFull page for that param set
Intermediate (build list)Intermediate fallbackFull page for remaining params
Already upgraded variationFull pageRefresh 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 liveRebask html: / rsc: keys (memory or cacheHandler)Vercel prerender CDN entries
Shared shellOne key per route fileOne prerender pattern + allowQuery
Intermediate shellsBuild list; can refill known keys at runtime if missing/staleBuild routes and fallbacks only
Unknown comboShared → promote toward full pathname in Rebask cacheShared → full page in that allowQuery slot
ResumeApp streams shell + dynamic in one responseCDN shell, then resume POST to the function
"use cache"Your cacheHandler or defaultYour cacheHandler if set; otherwise Vercel Runtime Cache

HTML and RSC page bodies are not written through a custom cacheHandler on Vercel. Use cacheHandler for "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 and intermediate shells.

Images

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

  • If rebaskImage() 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 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 for the Rebask image configuration.

disablePrerender

Set disablePrerender: true only when you supply a custom cacheHandler 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.