🧠 Caching API Responses in Next.js: ISR, SSR, and Edge Cache Deep Dive
AKA how not to burn your server and your bandwidth bill.
1. ISR (Incremental Static Regeneration)
“Let’s pretend the page is static… until it’s not.”
🧐 What is it?
It’s like saying, “Build this page ahead of time, but if someone visits it and it’s stale, quietly build a new one in the background.”
Users get lightning-fast static pages, and you still serve semi-fresh data.
🧪 Use case:
- Blog posts, product pages, anything that doesn’t change every second.
- Need data to be updated every X seconds/minutes? Use ISR.
🧠 How you tell Next.js:
fetch('https://api.com/data', {
next: { revalidate: 60 } // “Yo Next.js, refresh this every 60 seconds.”
})
⚡ Magic:
- First request gets old content.
- In the background, it regenerates the page.
- Second user gets the shiny new version.
- You? You chill. No full rebuilds needed.
🧓 Wisdom:
“It’s static. But cooler. And lazier. Just like most devs on Fridays.”
2. SSR (Server-Side Rendering)
“I want the latest data. No excuses. Build it now.”
🧐 What is it?
Every request = fresh page from the server. No caching unless you manually cache.
Feels like 2005 with smarter tooling.
🧪 Use case:
- Dashboards, admin panels, analytics.
- Stuff where you’d be yelled at if stale data shows up.
🧠 How you tell Next.js:
fetch('https://api.com/live', {
cache: 'no-store' // “Don’t even *think* about caching this.”
})
export const dynamic = 'force-dynamic' // Force SSR even if you forget something
⚡ Magic:
- User hits the page.
- Server panics, builds everything fresh.
- You serve up-to-date data at the cost of a few milliseconds and CPU tears.
🧓 Wisdom:
“If your data changes every second and you still use static... we need to talk.”
3. Edge Caching (aka CDN-fu)
“Let’s render stuff closer to the user... like psychic fast.”
🧐 What is it?
Next.js deploys your logic on the Edge runtime (yes, like on Cloudflare or Vercel’s Edge Network). You slap a Cache-Control
header, and now your data is cached at 200+ locations globally.
🧪 Use case:
- Geo-personalized pages
- High-traffic, low-latency API responses
- “We’re going viral and can’t afford latency!”
🧠 How you tell Next.js:
export const runtime = 'edge'
return Response.json(data, {
headers: {
'Cache-Control': 'public, max-age=120' // Cache at edge for 2 mins
}
})
Or use:
fetch('https://api.com/edge-stuff', {
next: { revalidate: 120 } // Same as ISR, but you’re doing it from the edge
})
⚡ Magic:
- Requests go to the nearest edge server.
- Responses get cached there.
- Users around the globe say “wow”.
- Your backend server sighs in relief.
🧓 Wisdom:
“Why fight latency when you can cache globally and sip your coffee in peace?”
🧾 TL;DR Table (Sticky Note Version)
Strategy | Use When | Freshness | Speed | Config |
---|---|---|---|---|
ISR | Static-ish data | Revalidates on interval | ⚡ Fast | revalidate: 60 |
SSR | Real-time data | Always fresh | 🐢 Slow-ish |
cache: 'no-store' + dynamic: 'force-dynamic'
|
Edge | Global + fast data | Configurable | ⚡⚡⚡ Ridiculously fast |
runtime: 'edge' + Cache-Control
|
🚀 Pro Tips (a.k.a. “You’ll thank me later”)
- API Route + ISR = amazing if you want to cache data responses instead of pages.
-
revalidateTag()
= revalidate specific pages or APIs when something changes (Next.js 13.4+). - Dev mode lies – caching doesn’t behave exactly in dev. Always test in production/staging.
- Avoid
cache: 'force-cache'
unless you know what you’re doing. It’ll aggressively cache everything like it’s hiding gold.