Skip to main content

Stale-while-revalidate configured for APIs

ab-002029 · performance-deep-dive.caching-cdn.stale-while-revalidate-apis
Severity: highactive

Why it matters

Every read-only API endpoint that responds with no-cache forces the browser to wait for a full network round-trip before rendering data — even for data that changes infrequently. stale-while-revalidate flips this: the browser serves the last cached response immediately (zero perceived latency), then fetches a fresh copy in the background. ISO 25010:2011 time-behaviour measures the round-trip cost; the user-visible gain is instant page paint for the common case, with fresh data arriving shortly after.

Severity rationale

High because serving all API responses with `no-cache` forces users to wait for a full network round-trip on every data fetch, adding hundreds of milliseconds to perceived load time even when cached data would be adequate.

Remediation

Add Cache-Control: public, max-age=60, stale-while-revalidate=86400 to API responses where serving slightly stale data is acceptable. Exclude personalized or mutation endpoints — those must use private, no-cache.

// app/api/products/route.ts
export async function GET() {
  const products = await fetchProducts()
  return Response.json(products, {
    headers: { 'Cache-Control': 'public, max-age=60, stale-while-revalidate=86400' },
  })
}

Detection

  • ID: performance-deep-dive.caching-cdn.stale-while-revalidate-apis

  • Severity: high

  • What to look for: Count all API endpoints. Enumerate which return stale-while-revalidate in their Cache-Control headers vs. no-cache. Examine API response headers or middleware/service worker code for the stale-while-revalidate directive. Check for patterns where cached data is served immediately while a fresh fetch happens in the background.

  • Pass criteria: API endpoints use Cache-Control: public, max-age=60, stale-while-revalidate=86400 (or equivalent). Users receive cached data instantly while fresh data is fetched in background. At least 50% of read-only API endpoints should use stale-while-revalidate.

  • Fail criteria: API responses do not use stale-while-revalidate. Users wait for network fetch even if cached data is available.

  • Skip (N/A) when: The project has no API endpoints or all API responses are highly dynamic and not cacheable.

  • Cross-reference: For edge caching of personalized content, see the edge-cache-personalization check.

  • Detail on fail: "API endpoints use Cache-Control: no-cache — cached data never served, users always wait for fresh fetch" or "No Cache-Control header on API responses"

  • Remediation: Add stale-while-revalidate to API responses so users get instant cached data while fresh data loads in background.

    // app/api/products/route.ts — stale-while-revalidate caching
    return Response.json(data, { headers: { 'Cache-Control': 'public, max-age=60, stale-while-revalidate=86400' } })
    

External references

Taxons

History