deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Nuxt SWR caching can replay one visitor's cookies and content to other users, dev.to post shows

A dev.to post reproduces three ways Nuxt's stale-while-revalidate route caching can hand one visitor's cookies, host data and currency to everyone, with fixes for each.

Nuxt SWR caching can replay one visitor's cookies and content to other users, dev.to post shows

One cache key, many visitors

Enabling stale-while-revalidate caching in Nuxt takes a single line of routeRules configuration — swr: 60 on a route pattern — and, according to a dev.to post by Muhammad Usama, can cut time-to-first-byte from seconds down to milliseconds. The catch is architectural: the cached response is produced once, for a single request, and is then handed to every subsequent request that resolves to the same cache key. On a personalized site, that is how one visitor's data ends up in another visitor's browser.

The author writes that he first ran into these problems while caching a large e-commerce storefront, then rebuilt each scenario in a minimal app running Nuxt 4.5.2 and Nitro 2.13.4 to confirm the behavior is real rather than an artifact of his production setup.

Trap 1: cookies set during rendering are replayed

The first reproduction is a page that assigns an A/B testing bucket during server-side rendering with useCookie. With caching enabled on the route, three new visitors all received the identical Set-Cookie header — the bucket value generated for the first render was replayed to everyone who hit the cached entry. As the post explains, the Set-Cookie header is stored together with the cached response, so the whole experiment collapses into a single bucket.

The contrast points to the fix: the same kind of cookie set in server middleware was not cached, because middleware runs on every request before the cache is consulted. The recommendation is to set per-visitor cookies in server/middleware rather than in pages, components or plugins, and to write the cookie only when the value actually changes.

Trap 2: multiple hosts share one entry

The second trap affects deployments where a single app serves several hosts — separate stores, tenants or country domains. Because the default cache key is path-based, whichever host renders first wins: in the author's lab, both test stores received the host value captured by the first render. The fix he verified is to add cache: { varies: ['host', 'x-forwarded-host'] } to the route rule, which gives each host its own cache entry while requests still hit the cache.

Trap 3: personalized content frozen into the HTML

The third reproduction is a page that reads a currency cookie during SSR. Visitors sending EUR and PKR cookies both received the currency baked in by the first, cookieless render. The post lists the fixes in order: keep personalized UI out of server rendering entirely, using ClientOnly or a client-side fetch; render a neutral value and correct it on the client; vary the cache key only across a small, bounded set of values — never by a per-visitor cookie; or leave the route uncached. The author cautions that if prices also depend on experiments or segments, checking currency alone will not catch every case.

A quick audit with curl

The post also describes a cheap test for an existing site: request a cached route twice as two fresh visitors and compare Set-Cookie headers one by one rather than as a block, because a legitimately fresh cookie issued by middleware can sit alongside a replayed one. Any cookie carrying the same value on both requests is coming from the cache.

Why it matters

Route-level SWR caching is one of the most accessible performance wins in Nuxt, and that accessibility is precisely the risk. The failure mode is silent and intermittent — it only appears for later visitors inside the cache window — so it never shows up in single-user testing. A replayed Set-Cookie header can quietly collapse an A/B test into one bucket or, with a session-like cookie, expose one visitor's state to another. A path-only cache key on a multi-tenant app can serve the wrong store's content and pricing. What makes this post useful is that each trap is reproducible in a minimal app, each has a concrete fix, and the audit is a two-command curl check that can run against staging today. The author says he has documented seven traps in total — including an ERR_HTTP_HEADERS_SENT error during revalidation, state leaking across client navigation, per-process cache storage and CLS measurement mistakes — alongside a lab app, a leak-test script and a repository-scanning audit command.

  • #nuxt
  • #ssr
  • #caching
  • #web-performance
  • #vue