Workers Cache demo
vinext ships two Cloudflare cache adapters you declare in vite.config.ts:
cdnAdapter()serves page-level ISR through the Cloudflare Workers Cache (ctx.cache). The origin renders fresh and the edge absorbs HIT/STALE traffic, revalidating in the background;revalidateTag()/revalidatePath()fan out toctx.cache.purge({ tags }).kvDataAdapter()backs the inner"use cache"/ fetch data cache with a Workers KV namespace instead of in-memory.
Both are wired up in vite.config.ts:
import { cdnAdapter } from "@vinext/cloudflare/cache/cdn-adapter";
import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";
vinext({
cache: {
cdn: cdnAdapter(),
data: kvDataAdapter(), // binding defaults to VINEXT_KV_CACHE
},
});
cdnAdapter() generates the per-entrypoint Workers Cache configuration during
the Cloudflare build. The KV adapter still needs a matching
VINEXT_KV_CACHE namespace binding in wrangler.jsonc.
The adapter adds a transport-only URL digest so distinct response-stage identities cannot collide. Workers Cache owns this key independently of zone Cache Rules.
What's in the box
- ISR-cached App Router page at
/cached/[slug](revalidate = 60). - Cached App Route handler at
/api/now(revalidate = 30). - Force-dynamic comparison page at
/dynamic. - Revalidation API at
/api/revalidate-tagand/api/revalidate-paththat drives the UI's "Invalidate this page" controls. - A client-side probe that issues a no-store fetch against a route and
prints the headers Cloudflare's edge attaches —
cf-cache-status(the outer Workers Cache verdict),Age, plus theCache-Control/Cache-Tagheaders vinext emits to drive it.
How vinext wires it up
-
vite.config.tsdeclares the adapters viavinext({ cache })(see above). The declarations do not touch the Workers runtime during config evaluation. The Cloudflare build hook emits the staged Worker configuration, and runtime adapters instantiate lazily on the first request. -
wrangler.jsoncbinds the KV namespace:{ "kv_namespaces": [{ "binding": "VINEXT_KV_CACHE", "id": "<your-kv-namespace-id>" }], }Create the namespace with
npx wrangler kv namespace create VINEXT_KV_CACHEand drop the returned id in. -
The Worker entry uses vinext's router-selected handler directly from
wrangler.jsonc:{ "main": "vinext/server/fetch-handler", }When
cdnAdapter()is configured, vinext asks the Cloudflare build for two Worker entrypoints. The default entrypoint runs routing and middleware with caching disabled;VinextCachedResponselazily loads the render stage with Workers Cache enabled. The generateddist/server/wrangler.jsoncontains those settings, so existing applications do not need a source-config edit. The handler also passes the Worker'senvsokvDataAdapter()can resolve its KV binding. No manual registration. -
ISR responses carry
Cloudflare-CDN-Cache-Control: public, max-age=N, stale-while-revalidate=M(for the edge) plus a browser-facingCache-Control: public, max-age=0, must-revalidate, and aCache-Tagheader listing both the bare path (/cached/intro) and Next.js's internal_N_T_<path>form. The Workers Cache reads these to cache and tag-purge. -
revalidateTag/revalidatePathin your route handlers fan out to both the KV data cache andctx.cache.purge(...)on the platform layer.
Running locally
pnpm install
pnpm dev
Then open http://localhost:5173 and click into any of the demo routes.
Note: dev runs on
@cloudflare/vite-plugin(miniflare), so theVINEXT_KV_CACHEnamespace is emulated locally andkvDataAdapter()works. The edge CDN layer (cf-cache-status, background revalidation) only runs on Cloudflare's edge — locally theCloudflare-CDN-Cache-Control/Cache-TagheaderscdnAdapter()emits are what drive it once deployed.
Deploying
pnpm build
npx wrangler deploy