An API endpoint that returns product listings or blog posts without a Cache-Control header causes every client request to hit the origin server — even when the data hasn't changed in hours. At scale, this is avoidable server load that accumulates into real infrastructure cost and latency. Conversely, a user-specific endpoint (account data, cart, session) served with Cache-Control: public allows CDN or browser caching to serve one user's data to another — a privacy violation. ISO 25010 performance-efficiency.resource-utilization applies: public data should be cached to eliminate redundant computation; private data must be protected from shared caches.
Low because missing API cache headers waste server resources on repeated identical requests, but the impact is gradual and does not block functionality until traffic scales.
Add explicit Cache-Control headers to all API GET routes. Public data (product lists, blog posts, public stats) should be cached; user-specific data (account info, cart, orders) must be marked private or uncacheable.
// Next.js App Router — src/app/api/products/route.ts
export async function GET() {
const products = await db.products.findAll()
return Response.json(products, {
headers: {
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400'
// CDN caches for 1 hour, serves stale for 24h while revalidating
}
})
}
// User-specific data — must be private
export async function GET(request: Request) {
const user = await getAuthenticatedUser(request)
return Response.json(user, {
headers: {
'Cache-Control': 'private, no-cache'
// Never cache in shared (CDN) cache
}
})
}
ID: performance-load.caching.api-cache-strategy
Severity: low
What to look for: Count all API route files in the project. For each GET endpoint, check whether a Cache-Control header is set in the response. Classify each as: (a) public data with appropriate cache headers (public, max-age=...), (b) private/user-specific data with appropriate headers (private, no-cache or no-store), or (c) no cache headers set. Enumerate: "X API routes found, Y set explicit Cache-Control headers."
Pass criteria: At least 50% of API GET endpoints set explicit Cache-Control headers. Public data endpoints use Cache-Control: public, max-age=... with max-age of at least 60 seconds. User-specific endpoints use Cache-Control: private, no-cache or no-store. No more than 2 API routes should rely on browser default caching. Report: "X of Y API GET routes set explicit Cache-Control headers."
Do NOT pass when: A public-data endpoint (e.g., product listings, blog posts) returns user-specific data headers (private) or no cache headers at all, causing every request to hit the server.
Fail criteria: Fewer than 50% of API GET endpoints set any Cache-Control header, or a public data endpoint is marked as private/no-store.
Skip (N/A) when: No API routes detected (0 API route files found — the project has no backend endpoints).
Detail on fail: "1 of 6 API GET routes sets Cache-Control — /api/products, /api/posts, and /api/categories all lack cache headers" or "User profile endpoint at /api/user uses Cache-Control: public — violates privacy for 500+ users"
Remediation: Add cache headers to API routes:
// Next.js API route — public data
export async function GET() {
const data = await db.products.findAll()
return Response.json(data, {
headers: {
'Cache-Control': 'public, max-age=3600' // cache for 1 hour
}
})
}
// User-specific data
export async function GET() {
const user = await getAuthenticatedUser()
return Response.json(user, {
headers: {
'Cache-Control': 'private, no-cache'
}
})
}