The Worker request pipeline
Everything createDecoWorkerEntry does with a request on TanStack Start, in order, from opening the request scope to the edge cache and the response headers.
On TanStack Start, every request reaches your site through createDecoWorkerEntry before TanStack sees it (see TanStack Start on Cloudflare Workers). This page lists what it does, in order. It's useful when a request behaves unexpectedly: a page served from cache when you expected a fresh one, an admin route answered by your app, a redirect that doesn't fire.
The pipeline has three parts: preparing the request, routing it (most branches answer and stop), and finishing the response. TanStack Start renders a page only when a request reaches the last branches of the routing part.
1. Preparing the request
These steps run for every request:
- Location cookies. With
autoInjectGeoCookies(the default), Cloudflare's geolocation for the visitor is copied into request cookies that matchers read. They exist only inside the Worker and are never sent to the browser. - Request scope. Everything after this runs inside a request context for this request, so loaders and helpers anywhere can read it.
- Content. With Fast Deploy on, the first request in a Worker instance loads the current decofile from KV, and the instance checks for a newer revision at most every 10 seconds. Without it, the content bundled with the build is used.
- Apps. Installed apps are configured from their blocks the first time, and again after the content changes.
- Tracing. The request gets an id (the incoming
x-request-id, or a new one) and joins the caller's trace when atraceparentheader is present.?__dforces this request's trace to be recorded. - Draft preview. If the request carries a valid draft link or cookie for an allowed host, the draft's content is used for this request only. See Draft preview.
- Security nonce. With
cspMode: "enforce", a per-request nonce is generated for inline scripts. - App middleware. Apps that ship middleware (VTEX, for example) wrap the routing step, so they can read and set cookies around everything that follows.
2. Routing
The Worker tries each branch in this order. The first one that answers ends the routing.
- Admin protocol.
/live/_meta,/.decofile,/live/previews/*and the liveness check go to theadminhandlers you passed in. They're never cached. See Site Editor and the v7 admin protocol. - Purging.
POST /_cache/purgeandPOST /_cache/purge-loaders, with the purge token. See Caching. - CMS redirects. Redirect blocks from the content, and with Fast Deploy also the redirects stored in KV. Exact paths are checked before patterns, across both sources. A match answers with its status (301 or 302) and
Location. See Pages and routing. - Page JSON.
?renderJsonand?asJsonon a page URL return the resolved page as JSON instead of HTML, unless turned off. See Storefront as an API. - Your proxy.
proxyHandler, if set, gets a chance to answer, typically by forwarding checkout and account paths to the commerce platform. - Static assets. Fingerprinted build assets are served with a one-year immutable cache. An asset path that comes back as HTML (a missing file falling through to the app) becomes a 404.
- Server functions.
POSTrequests to TanStack's server-function endpoints carry page data and deferred sections. They're cached at the edge with thelistingprofile, keyed on a hash of the request body plus the dimensions listed below, and only when the response marks itself cacheable and sets no cookie. Draft, logged-in and matcher-override requests bypass the cache. - Requests that aren't cacheable. Anything other than
GET, the bypass paths (/deco/,/live/,/.decofile,/_buildand your own), draft and preview requests, and requests that force matcher results go straight to TanStack. If the URL's cache profile isprivate,noneorcart, the response is markedno-store. - Cacheable pages. Everything else is a cacheable
GET, handled by the edge cache in the next section.
3. The edge cache
For a cacheable request, the Worker builds a cache key, then looks it up in Cloudflare's Cache API:
- Logged-in visitors (
loggedIn: truefrombuildSegment) skip the cache entirely and always get a fresh render. - Fresh hit (
X-Cache: HIT): the stored response is returned. - Stale hit (
X-Cache: STALE-HIT): within the profile's stale-while-revalidate window, the stored response is returned at once and a fresh one is rendered in the background to replace it. - Miss (
X-Cache: MISS): TanStack renders the page. The result is stored only if it's a200, isn't degraded, sets no cookies other than the safe ones (which are removed from the stored copy), its profile is public, and the request carried no tracking parameters. - Origin failure. If rendering throws, returns a 5xx or a 429, or produces a degraded page, and a stored copy is still within the profile's stale-if-error window, that copy is served (
X-Cache: STALE-ERROR). Otherwise the response passes through uncached.
The cache is skipped in local development. Caching explains every X-Cache and X-Cache-Reason value.
What the cache key includes
Two requests share a cached response only if all of these are the same:
| Dimension | Notes |
|---|---|
| The URL | Path and query string, with tracking parameters (utm_*, gclid and the like) removed. |
| The deploy | Each build gets its own cache namespace, from BUILD_HASH or the hash the Vite plugin injects. A deploy never serves the previous build's pages. |
| The segment | What buildSegment returns (device, sales channel, region, flags and custom keys). Without buildSegment, the device class, unless deviceSpecificKeys is false. |
| Location | Added when geoCacheKey asks for it, or in "auto" mode when the content uses the location matcher. |
| Crawler or human | Crawlers get every section server-rendered, so they have their own entries. |
| Programmatic fetch | Requests with Sec-Fetch-Dest: empty (a script fetching the page) also get everything server-rendered, and their own entries. |
| A/B cohort | The visitor's assigned variants from random-split tests. |
Cookies, other headers and the logged-in visitor's identity are never part of the key, which is why logged-in visitors bypass the cache and why responses that set private cookies aren't stored.
4. Finishing the response
Whatever branch answered, the response then gets:
- Cookie cleanup. Duplicate
Set-Cookieheaders for the same cookie are reduced to the last one. - CDN instructions. A
CDN-Cache-Controlheader for Cloudflare's CDN in front of the Worker. Bypassed responses, and any without one, getno-store. See Caching. - Security headers on HTML responses, from
securityHeadersandcsp, including theframe-ancestorspolicy that lets Studio frame the site. - Identification:
x-request-id,x-trace-idwhen the request was traced, andx-powered-by. - Draft cookies. Setting or clearing the draft-preview cookie, and the headers that keep draft responses out of caches and search indexes.
- Telemetry. A request metric with the method, status, duration and cache decision. With
DECO_OTEL_*endpoints configured, traces, metrics and logs are exported; see Observability.
Next steps
- TanStack Start on Cloudflare Workers: every option of
createDecoWorkerEntry. - Caching: profiles, segments and purging in depth.
- How resolution works: what happens when TanStack renders a page.