perf hacks
CachingCDN Cache

CDN Cache

Cache API responses at the edge. When this works, your function doesn't run at all.

Maximum Savings

CDN caching is the outermost cache layer. When a response is cached at the edge, your function doesn't run at all - that's zero compute cost.

User Request → CDN: "Have I seen this?"
  → Yes: Return cached (FREE)
  → No: Call function, cache, return

Setting Cache Headers

app/api/products/route.ts
export async function GET() {
  const products = await db.products.findMany();

  return Response.json(products, {
    headers: {
      'Cache-Control': 'public, s-maxage=300',
      'Stale-While-Revalidate': '3600',
    },
  });
}

Key Headers

HeaderPurpose
s-maxage=300Cache at CDN for 5 minutes
stale-while-revalidate=3600Serve stale while fetching fresh
publicAllow CDN caching
privatePrevent CDN caching (user data)

The Auth Gotcha

Reading cookies or auth headers busts the cache:

// ❌ Won't cache - reads cookies
export async function GET(request: Request) {
  const session = request.cookies.get('session');
  // ...
}

Fix: Separate public and private endpoints:

app/api/products/public/route.ts
export async function GET() {
  return Response.json(await getPublicProducts(), {
    headers: { 'Cache-Control': 'public, s-maxage=300' },
  });
}

// app/api/products/mine/route.ts - Not cached
export async function GET(request: Request) {
  const user = await getUser(request);
  return Response.json(await getUserProducts(user.id));
}

Debugging

Check Vercel Dashboard → Analytics → Cache for hit rates.

Low hit rate? You're probably reading cookies/headers somewhere.


Next: Route Cache for caching entire pages.

On this page