Vercel CDN skips Vary: Cookie responses: Sume status proxy headers

Vercel's CDN no longer caches Vary: Cookie responses. For a route proxying Sume job status, send Cache-Control private and honor next_poll_after_seconds.

4 min readSume
All posts

A route that proxies Sume job status is personal to the caller, so it should not sit in a shared cache whatever Vercel's CDN does. Send Cache-Control: private, no-store on it and let the client honor next_poll_after_seconds.

Vercel facts are from its September 30 changelog entry; Sume facts from Communication modes and Authentication, read 2026-10-01.

What changed on Vercel?

The entry says the CDN no longer caches origin responses when Vary includes Cookie. To spot it, look for x-vercel-cache: MISS and the Runtime Logs reason vary_key_denied:cookie. The fix depends on the response: if it does not depend on cookies, remove Cookie from Vary; if it is personalized, keep Vary and add Cache-Control: private. Caching for other supported Vary headers is unchanged.

Vercel guidance for Vary: Cookie, from its changelog read 2026-10-01
ResponseAction
Does not depend on cookiesRemove Cookie from Vary
PersonalizedKeep Vary, add Cache-Control: private

Is a Sume status route cacheable?

Not in a shared cache. Job status changes as the job moves through queued, processing and a terminal state, and it belongs to one workspace. Caching it would serve one caller's job to another or hold a stale processing. The Sume status payload's next_poll_after_seconds tells the client when to ask again; that is the pacing signal, not a CDN TTL.

What does the route send?

Forward the status body and set private headers. Check that the caller owns the job id before you proxy it; the example leaves that to your auth layer.

export async function GET(
  _req: Request,
  { params }: { params: Promise<{ id: string }> },
) {
  const { id } = await params;
  const res = await fetch(
    "https://api.sume.com/v1/jobs/" + encodeURIComponent(id) + "/status",
    { headers: { "x-api-key": process.env.SUME_API_KEY ?? "" }, cache: "no-store" },
  );
  return new Response(res.body, {
    status: res.status,
    headers: {
      "content-type": "application/json",
      "cache-control": "private, no-store",
    },
  });
}

How much polling can the proxy afford?

One key has one budget. Reads and writes are separate, with Free at 4,800 reads and 120 writes per minute and Scale at 48,000 and 1,200, so a busy status route cannot 429 your submits. Still, many browsers behind one key share that read budget; see the read and write limits post.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume