ISR (Incremental Static Regeneration) is stale-while-revalidate — not instant refresh. After revalidate:N seconds, the NEXT request triggers regeneration, not the current one
The 'stale window' is the time between the data change and the first server request that triggers regeneration — during which every user sees stale data
On-demand revalidation via revalidatePath() or revalidateTag() eliminates the stale window by invalidating immediately when data changes
generateStaticParams pre-generates routes at build time — ISR fills in missing routes at request time with fallback behavior
Stale-while-revalidate means: serve cached (possibly stale), regenerate in background, swap on completion — current visitor gets stale data
Biggest mistake: thinking revalidate:N means 'refresh every N seconds'. It means 'regenerate at most every N seconds' — these are not the same thing
✦ Definition~90s read
What is Incremental Static Regeneration (ISR) in Next.js 16?
Incremental Static Regeneration (ISR) is a Next.js feature that allows static pages to be updated after the build step without requiring a full redeployment. ISR implements the stale-while-revalidate caching pattern: a page is statically generated at build time or on first request, cached, and then regenerated in the background when the revalidation timer expires.
★
ISR is like a newspaper delivery service that prints a batch of papers at 6 AM and promises to re-print at most every 60 minutes.
The revalidate configuration option (e.g., revalidate: 60) defines the minimum time between regenerations — not the maximum time before a page updates.
The core mechanism: when a request arrives for an ISR page, Next.js checks if the cached version is still within the revalidation window. If so, it returns the cached version immediately — zero server-side computation. If the window has expired, it returns the cached version anyway (stale) and triggers a background regeneration.
The regeneration starts when the response has been sent, not before — so the current visitor always sees the stale version. Future visitors see the freshly regenerated page.
On-demand revalidation via revalidatePath() and revalidateTag() extends ISR with immediate invalidation. When your CMS or data source changes, you call revalidatePath('/products/slug') to mark that specific path as stale, or revalidateTag('products') to invalidate all pages that fetch data tagged with 'products'.
The next request triggers regeneration without waiting for the timer. This eliminates the staleness window for known data changes while retaining the performance benefits of cached responses for all other requests.
ISR is best suited for content that changes on a predictable schedule and where brief staleness is acceptable — blog posts, product catalogs, documentation. For time-sensitive data like pricing, inventory, or user-specific content, ISR should be combined with PPR streaming (no-store fetches in Suspense boundaries) or avoided entirely in favor of dynamic rendering.
Plain-English First
ISR is like a newspaper delivery service that prints a batch of papers at 6 AM and promises to re-print at most every 60 minutes. If breaking news happens at 6:05 AM, the 6 AM papers still say the old news — the new print run doesn't start until the 60-minute timer expires. Worse: when the timer expires, the print run starts for the NEXT customer who asks, not the current one. So the current customer gets old news, and the new print run serves the next customer. On-demand revalidation is like a phone call to the printing press: 'stop the press, update the front page right now.' The stale window goes from 60 minutes to zero.
⚙ Browser compatibility
Latest versions — ✓ supported
Chrome
Firefox
Safari
Edge
✓
✓
✓
✓
Incremental Static Regeneration (ISR) is one of Next.js's most misunderstood features. The documentation says 'revalidate: 60' regenerates the page at most every 60 seconds. Most developers interpret this as 'the page refreshes every 60 seconds.' It does not. ISR uses a stale-while-revalidate cache pattern: when the revalidation timer expires, the cached (stale) page continues serving the current visitor while a background regeneration is triggered. The regeneration happens for the NEXT visitor, not the current one.
This distinction matters during flash sales. A product goes from 'Out of Stock' to 'In Stock.' The CMS updates the inventory. ISR with revalidate: 60 means up to 58 seconds of users seeing 'Out of Stock' — because the timer started at the last regeneration, not at the CMS update. Users who wait and refresh at second 58 still see stale data. Only the user at second 61 triggers the regeneration.
In this article, you'll learn exactly how ISR works under the hood, how to measure the stale window, and the two patterns that eliminate it: on-demand revalidation and stale-while-revalidate headers at the CDN level.
How ISR Actually Works — The Stale-While-Revalidate Pattern
ISR is an implementation of the stale-while-revalidate caching pattern. When you set revalidate: 60, the first request after a build renders the page fresh and caches it. A timer starts. Any request within the next 60 seconds hits the cache — instant response, zero server-side rendering. When the timer expires (at second 61), the NEXT request triggers a background regeneration. The current request still gets the stale cached page. The regeneration result replaces the cache and resets the timer.
This is the critical mental model: revalidate:N does NOT mean 'regenerate every N seconds.' It means 'allow at most N seconds to pass before the server CONSIDERS regenerating on the next request.' The actual regeneration interval depends on traffic patterns. A page with one request per hour will regenerate at most once per hour, regardless of revalidate value.
The stale window: the time between a data change and the first request that triggers regeneration. If data changes 1 second after a regeneration, the stale window is up to N seconds (the revalidate time). If data changes right when the timer expires, the next request triggers regeneration immediately — stale window of ~0 seconds.
ISR = Stale-While-Revalidate, Not a Cron Job
revalidate: N limits the MINIMUM time between regenerations — not the maximum staleness
The current visitor always gets the cached (possibly stale) page — regeneration is for future visitors
Traffic matters: a page with no requests in N seconds does not regenerate until the next request arrives
On-demand revalidation bypasses the timer completely — immediate regeneration on data change
Production Insight
The flash sale team had revalidate: 60, which they thought meant 'maximum 60 seconds of staleness.' In reality, the maximum staleness with ISR is 2N — N seconds from the timer plus N seconds from the regeneration window. During low traffic, it can be even longer. The restock happened 9 minutes after the timer started — staleness was 9 minutes, not 60 seconds.
Rule: revalidate:N is a lower bound on regeneration frequency, not an upper bound on staleness.
Key Takeaway
ISR uses stale-while-revalidate — current visitor gets stale data, regeneration is for the next visitor.
revalidate:N limits regeneration frequency, not staleness — actual staleness can be up to 2N seconds.
On-demand revalidation is the only way to eliminate the stale window completely.
thecodeforge.io
Nextjs Incremental Static Regeneration
The Stale Window — How to Measure and Minimize It
The stale window is the duration between a data change in your CMS or database and the moment the next ISR regeneration completes. It is determined by three factors: the revalidate timer (N seconds from last regeneration), the request arrival time (when the first user hits the page after the timer expires), and the regeneration duration (how long the fetch + render takes).
Worst case: data changes 1 second after a regeneration starts. The stale window is N seconds (timer expiry) plus the regeneration time. Best case: data changes right as the timer expires — the very next request triggers regeneration immediately.
You can measure the stale window by logging regeneration timestamps. Add a comment in your fetch or page that logs the build time. Compare it against CMS update timestamps in your analytics to see the actual staleness in production.
measure-stale-window.tsTYPESCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// ============================================// Measuring ISR Stale Window// ============================================// ---- Add a build timestamp to the page ----interfaceProduct {
id: string
name: string
price: number
inventoryStatus: string
}
exportdefaultasyncfunctionProductPage({
params,
}: {
params: { slug: string }
}) {
const buildTime = newDate().toISOString()
const product: Product = awaitfetch(
`https://api.example.com/products/${params.slug}`,
{ next: { revalidate: 60, tags: ['products'] } }
).then(r => r.json())
// Log staleness metrics
console.log({
event: 'ISR_SERVE',
slug: params.slug,
renderTime: buildTime,
dataTimestamp: product.updatedAt,
stalenessSeconds:
(Date.now() - newDate(product.updatedAt).getTime()) / 1000,
})
return (
<div>
<h1>{product.name}</h1>
<p className="text-2xl font-bold">${product.price}</p>
<BuyButton status={product.inventoryStatus} />
</div>
)
}
// ---- Add a version identifier for cache analysis ----// Include this in the page HTML for debuggingexportfunctionCacheVersion({ renderedAt }: { renderedAt: string }) {
return (
<script
dangerouslySetInnerHTML={{
__html: `window.__RENDERED_AT = "${renderedAt}";`,
}}
/>
)
}
ISR only regenerates when a request triggers it. During low-traffic periods, your revalidate timer expires but no regeneration happens until the next visitor arrives. A product page with revalidate: 60 that gets one request per hour regenerates at most once per hour — the stale window can be 59 minutes.
Production Insight
After the flash sale incident, the team added a monitoring cron that visits each product page every 30 seconds during flash sales, forcing ISR regeneration regardless of user traffic. This ensures the stale window never exceeds 30 seconds during critical events.
Rule: for time-sensitive events, add a synthetic monitoring service that generates traffic to force ISR regeneration, or switch to on-demand revalidation entirely.
Key Takeaway
Stale window = timer remaining + regeneration duration.
Worst case stale window can be 2N seconds — timer just started + regeneration time.
Low traffic extends the stale window — ISR only regenerates on request arrival.
On-Demand Revalidation — Eliminating the Stale Window
On-demand revalidation via revalidatePath() and revalidateTag() bypasses the ISR timer entirely. When your CMS, database, or any data source changes, you call revalidatePath('/products/slug') — the cached page is immediately marked as stale, and the next request triggers a fresh render. No waiting for the timer.
revalidatePath invalidates a specific route path. revalidateTag invalidates all fetch() calls tagged with a given tag — regardless of which pages they're on. Use revalidatePath when a specific page changes. Use revalidateTag when data shared across multiple pages changes.
Both functions can be called from Route Handlers (API routes), Server Actions, or webhook endpoints. The typical pattern: expose a /api/revalidate endpoint that accepts a secret token and a path or tag, called by your CMS via webhook.
Use revalidate:N as a safety net (fallback for when the webhook fails), and on-demand revalidation as the primary invalidation mechanism. revalidate: 3600 means 'if the webhook doesn't fire for some reason, stale data persists for at most 1 hour.' On-demand revalidation via webhook means 'invalidate immediately when data changes.'
Production Insight
After adding on-demand revalidation, the flash sale team's stale window dropped from 58 seconds to under 200ms — the time it took for the CMS webhook to reach their API endpoint and trigger regeneration.
Rule: on-demand revalidation is not optional for time-sensitive data. It is the primary invalidation mechanism. ISR revalidate:N is the safety net.
Key Takeaway
On-demand revalidation eliminates the ISR stale window completely.
revalidatePath for specific routes, revalidateTag for cross-page data.
Always pair ISR with on-demand revalidation — revalidate:N is the fallback, not the primary mechanism.
ISR: Time-Based vs On-Demand RevalidationTrade-offs between stale window and instant updatesTime-Based (revalidate: 60)On-Demand RevalidationStale WindowUp to 58s of stale contentZero stale windowCache FreshnessDepends on timer intervalInstant on data changeServer LoadPeriodic revalidation spikesEvent-driven, lower loadFlash Sale SuitabilityRisk of showing old pricesAlways up-to-dateImplementation ComplexitySimple, just set revalidateRequires webhook or API callTHECODEFORGE.IO
thecodeforge.io
Nextjs Incremental Static Regeneration
generateStaticParams — Pre-Building vs On-Demand Generation
generateStaticParams tells Next.js which routes to pre-render at build time. Combined with ISR, it enables a hybrid: the most popular or critical routes are pre-built (fastest), while less common routes are generated on first visit and then cached via ISR.
The function returns an array of params objects, one per route. Each route is statically generated at build time and included in the Full Route Cache. Routes not returned by generateStaticParams are handled by the fallback behavior you configure.
Fallback options: 'blocking' (wait for the page to generate on first request — SSR-like experience but cached afterward), true (immediately return a loading state, generate in background — not recommended for most cases), or false (return 404 for unlisted routes). For ISR, 'blocking' is the most common choice — first visitor triggers generation, subsequent visitors get the cached page.
Pre-build your top 500 products at build time. Use ISR with fallback: 'blocking' for the remaining 10,000 less-visited products. The first visitor to a less-visited product generates it on-demand. The next 100 visitors get the cached ISR version. This keeps build times fast while covering your entire catalog.
Production Insight
A team with 50,000 products pre-built all of them at build time. Build time: 45 minutes. Switching to top-500 pre-built + ISR fallback for the rest dropped build time to 3 minutes. The remaining products were generated on first visit and cached — subsequent visits were identical in speed to pre-built pages.
Rule: do not pre-build every route. Pre-build your top traffic routes and use ISR with fallback: 'blocking' for the long tail.
Key Takeaway
generateStaticParams pre-builds routes at build time — fastest response for pre-built routes.
ISR with fallback: 'blocking' generates on first visit and caches — good for long-tail content.
Hybrid approach: pre-build top routes, ISR-fallback for the rest.
ISR + CDN: How Edge Caching Interacts with Stale-While-Revalidate
When you deploy Next.js behind a CDN (Vercel Edge, Cloudflare, Akamai), the CDN adds another caching layer above ISR. The CDN's Cache-Control headers determine how long it holds the response before checking the origin. If your CDN caches the page for 300 seconds, even ISR with revalidate: 10 won't help — the CDN serves its cached copy regardless of what the Next.js server has.
Configure CDN caching via the response's Cache-Control header. For ISR pages, set s-maxage equal to your revalidate value, and add stale-while-revalidate to allow the CDN to serve stale during regeneration. The CDN then becomes part of the stale-while-revalidate chain: browser -> CDN -> edge -> Next.js.
The recommended pattern: set Cache-Control: public, s-maxage=60, stale-while-revalidate=30 on ISR pages. The CDN caches for 60 seconds, then serves stale for up to 30 more while revalidating. This gives you a total staleness bound that's predictable.
If your CDN caches a page for 5 minutes, ISR with revalidate: 10 is meaningless — the CDN serves its cached copy until its own TTL expires. Always align CDN s-maxage with your ISR revalidate value, and consider purging the CDN cache when you trigger on-demand revalidation.
Production Insight
The flash sale team discovered their CDN (Cloudflare) was caching product pages for 300 seconds by default — overriding their ISR revalidate: 60. The CDN's stale copy was what users saw, not the freshly regenerated ISR page. They added CDN cache purge to their webhook handler, and set explicit s-maxage headers matching their ISR configuration.
Rule: ISR configuration is only half the story. You must also configure your CDN to respect your ISR timings.
Key Takeaway
CDN caching sits above ISR — CDN s-maxage must match ISR revalidate value.
stale-while-revalidate at the CDN level adds another layer of controlled staleness.
Purge CDN cache alongside on-demand revalidation for complete invalidation.
ISR Patterns: When to Use It and When to Avoid It
ISR is ideal for content that changes predictably on a schedule: blog posts (every few hours), product catalogs (hourly), documentation (daily). It is dangerous for content that changes unpredictably or has high business cost of staleness: pricing, inventory, user-specific data.
Use ISR when: your content changes on a known schedule, you can tolerate N seconds of staleness, your traffic is sufficient to trigger regeneration, and you have on-demand revalidation as a fallback.
Avoid ISR when: data changes in real-time (chat, notifications), data is user-specific (dashboard, account settings), the cost of stale data is high (pricing, inventory, compliance content), or traffic is very low (single regeneration per hour despite revalidate: 60).
For high-stakes data, use PPR streaming with no-store fetches. The buy button on a product page should always be fresh — wrap it in a Suspense boundary and use cache: 'no-store'. The product description can be ISR with revalidate: 3600. Mix strategies on the same page.
ISR handles the 80% of data that changes on a predictable schedule
PPR + no-store handles the 20% of data that must always be fresh
Combine both on the same page — split by data freshness requirements
Avoid ISR for any data where staleness has business cost
Production Insight
The flash sale team now uses a hybrid approach: product descriptions and images are ISR with revalidate: 3600 (cached, stale-while-revalidate, acceptable), while the buy button and pricing are PPR-streamed with cache: 'no-store' (always fresh). The buy button was the critical piece — it never goes stale now.
Rule: use ISR for the slow-changing parts of a page, and PPR + no-store for the parts that must always be fresh.
Key Takeaway
ISR is for predictable-schedule content with acceptable staleness.
PPR + no-store is for real-time data where staleness has business cost.
Mix both strategies on the same page — different data, different freshness requirements.
ISR Debugging: How to Know If Your Cache Is Actually Regenerating
ISR operates silently. You don't get a notification when a page regenerates. You don't see a log by default. You must instrument your code to know whether ISR is working as expected.
Add logging to your page component to track when it renders and whether the cache hit or regenerated. Monitor the x-nextjs-cache response header: HIT means the request was served from the Full Route Cache (ISR cache). STALE means the cache expired and a regeneration was triggered. MISS means no cached version existed (first request or after invalidation).
Check your build output: next build shows which routes are static (○), ISR (●), or dynamic (ƒ). ISR routes are marked as ● with their revalidate value.
isr-debugging-commands.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# ============================================
# ISRDebuggingCommands
# ============================================
# === Build output: check which routes use ISR ===
# ○ = static, ● = ISR (with revalidate value), ƒ = dynamic
npx next build 2>&1 | head -50
# === Cache status header ===
# HIT = served from ISR cache
# STALE = cache expired, regeneration in progress
# MISS = no cache, fresh render
curl -I https://yoursite.com/products/slug | grep -i 'x-nextjs-cache'
# === CheckISR regeneration frequency ===
# Add server logs to your page component:
# console.log('ISR_RENDER', { slug, timestamp: Date.now() })
# Then grep your logs:
cat logs/app.log | grep 'ISR_RENDER' | tail -20
# === Force regeneration by visiting the page ===
# ISR regenerates on first request after timer expiry
curl https://yoursite.com/products/slug > /dev/null
# === Checkif the ISR page is serving fresh data ===
# Add a hidden timestamp to the page HTML:
# Then grep the output:
curl -s https://yoursite.com/products/slug | grep -o 'RENDERED_AT:[0-9]*'
Build ISR Logging Into Your Pages
Add a one-line log statement to every ISR page that logs the route, revalidate timer value, and a timestamp. Aggregate these logs to see regeneration frequency and verify that on-demand revalidation is working. Without logging, ISR is a black box.
Production Insight
The flash sale team now has a Grafana dashboard showing ISR regeneration frequency per route, cache hit ratios, and average stale window duration. They set up alerts when the stale window exceeds 30 seconds for any product page — triggers a manual revalidation and a team notification.
Rule: if you can't see when your cache regenerates, you can't trust your cache.
Key Takeaway
ISR operates silently — you must add logging to see regeneration frequency.
Monitor x-nextjs-cache header: HIT, STALE, or MISS.
Build a dashboard showing ISR regeneration metrics per route.
● Production incidentPOST-MORTEMseverity: high
58 Seconds of 'Out of Stock' Buttons During a Flash Sale
Symptom
A flash sale went live at 10:00 AM. By 10:05 AM, inventory sold out. At 10:10 AM, the CMS was updated to restock. But users continued seeing 'Out of Stock' on product pages until 10:11 AM — a full minute of lost sales. The product page used ISR with revalidate: 60.
Assumption
The team assumed revalidate: 60 meant 'the page checks for updates every 60 seconds' — like a cron job that refreshes the cache. They expected the page to update within seconds of the CMS restock.
Root cause
ISR's stale-while-revalidate pattern: the cached page was built at 10:00 AM. revalidate: 60 means the timer expired at 10:01 AM. But the regeneration only triggers on the FIRST request after the timer expires. Between 10:10 AM (restock) and 10:01 AM (timer expiry), no regeneration could start because the timer was still active. At 10:01 AM, the timer expired, but the build still ran with old data (10:00 AM inventory). The CMS restock at 10:10 AM triggered no regeneration because the revalidation timer was still running (started at 10:01 AM, expires 10:02 AM). Users who visited between 10:10 AM and 10:11 AM saw the 10:00 AM cached page because the timer hadn't expired yet. The earliest a regeneration with the restocked data could serve was 10:11 AM — 58 seconds after the CMS update.
Fix
1) Added on-demand revalidation: the CMS restock webhook now calls revalidatePath('/products/[slug]') immediately when inventory changes — no more waiting for the timer. 2) Kept revalidate: 300 as a fallback (5 minutes) in case the webhook fails. 3) Added a stale-while-revalidate CDN header: Cache-Control: public, s-maxage=60, stale-while-revalidate=30 — the CDN serves stale for up to 30 seconds while it revalidates in the background, reducing origin load. 4) Implemented a loading skeleton for the buy button specifically — always fresh via PPR streaming, never cached.
Key lesson
ISR revalidate:N is a cache expiry timer, NOT a refresh interval — the timer limits how OFTEN regeneration can happen, not when it does happen
The stale window is bounded by revalidate:N but can be as long as 2N seconds in worst case (timer just started when data changed)
On-demand revalidation eliminates the stale window entirely — always pair ISR with webhook-triggered revalidation for time-sensitive data
For mission-critical data like buy buttons, consider PPR streaming with no-store instead of ISR — always fresh, never stale
Production debug guideDiagnose and fix ISR-related stale data in production5 entries
Symptom · 01
Users see outdated content minutes after a CMS update despite revalidate: N
→
Fix
Check when the last regeneration happened — ISR only regenerates on the first request after the timer expires, not immediately on CMS update. Add on-demand revalidation via revalidatePath() triggered by a CMS webhook.
Symptom · 02
Some users see fresh data, others see stale data
→
Fix
ISR regenerates per-request at the edge. Users hitting a different edge node may get different versions until the regeneration propagates. Reduce revalidate:N or add on-demand revalidation to force global invalidation.
Symptom · 03
generateStaticParams produces too many pages at build time
→
Fix
Check if you have too many static paths. Use fallback: 'blocking' to generate pages on-demand instead of at build time. ISR will cache the generated page for subsequent requests.
Symptom · 04
Page regenerates on every request despite revalidate: N
→
Fix
Check if a dynamic API (cookies(), headers(), searchParams) forces dynamic rendering. ISR only works for statically analyzable routes. Move dynamic APIs into Suspense boundaries with PPR.
Symptom · 05
On-demand revalidation not taking effect
→
Fix
Verify the webhook reaches the server. Check that revalidatePath or revalidateTag strings match exactly (case-sensitive). Verify the secret matches. Check that the route isn't also cached behind a CDN that ignores the invalidation.
★ ISR Quick Debug ReferenceFast commands for diagnosing ISR staleness and regeneration behavior
Purge the CDN cache or add Cache-Control: no-cache to the response headers
⚙ Quick Reference
6 commands from this guide
File
Command / Code
Purpose
measure-stale-window.ts
interface Product {
The Stale Window
on-demand-revalidation.ts
export async function POST(request: NextRequest) {
On-Demand Revalidation
generate-static-params.ts
interface Product {
generateStaticParams
isr-cdn-config.ts
const nextConfig: NextConfig = {
ISR + CDN
isr-vs-ppr.ts
export default async function ProductPage({
ISR Patterns
isr-debugging-commands.sh
npx next build 2>&1 | head -50
ISR Debugging
Key takeaways
1
ISR uses stale-while-revalidate
the current visitor gets stale data, regeneration is for the next visitor
2
revalidate
N is a lower bound on regeneration frequency, not an upper bound on staleness
3
The stale window can be up to 2N seconds with time-based revalidation, or longer in low-traffic scenarios
4
On-demand revalidation via revalidatePath/revalidateTag eliminates the stale window completely
5
CDN caching sits above ISR
configure CDN s-maxage to match ISR revalidate values
6
Mix ISR with PPR streaming
ISR for the shell, PPR + no-store for critical data
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01SENIOR
Explain how ISR revalidate: 60 actually works under the hood. What is th...
Q02SENIOR
How would you eliminate the stale window for an e-commerce product page ...
Q03SENIOR
What is the difference between ISR and PPR in terms of data freshness?
Q01 of 03SENIOR
Explain how ISR revalidate: 60 actually works under the hood. What is the maximum staleness window?
ANSWER
ISR with revalidate: 60 implements stale-while-revalidate. The page is rendered fresh on first request after build and cached. The next 60 seconds of requests all hit the cache — no server rendering. After 60 seconds, the NEXT request triggers a background regeneration and serves the stale cached page to the current visitor. The regeneration result replaces the cache. Maximum staleness: up to 2N seconds (120 seconds) — N seconds from the timer starting just after the previous regeneration, plus N seconds until the regeneration completes if the timer expires at the right moment. In low-traffic scenarios, staleness can be much longer because regeneration only happens on request arrival, not on a fixed schedule.
Q02 of 03SENIOR
How would you eliminate the stale window for an e-commerce product page during a flash sale?
ANSWER
Eliminate the stale window by combining three strategies: 1) On-demand revalidation via webhook — the CMS calls revalidateTag('products') immediately when inventory or pricing changes, triggering instant regeneration regardless of the ISR timer. 2) Split the page into ISR shell + PPR streaming — the buy button and pricing stream via cache: 'no-store' in a Suspense boundary (always fresh), while product descriptions use ISR with revalidate: 3600 (acceptable staleness). 3) CDN cache purge after revalidation — call the CDN API to clear cached pages alongside Next.js revalidation, ensuring the edge cache doesn't serve stale data while the origin regenerates. 4) During flash sales, a synthetic monitoring service visits critical pages every 10 seconds to force ISR regeneration regardless of user traffic.
Q03 of 03SENIOR
What is the difference between ISR and PPR in terms of data freshness?
ANSWER
ISR serves cached pages with stale-while-revalidate — the entire page is cached and regenerated as a unit. Staleness is bounded by revalidate:N but the current visitor always gets potentially stale data. PPR (Partial Prerendering) splits the page into a static shell (cached, can be ISR-revalidated) and dynamic streaming holes (always fresh per request). With PPR, the dynamic parts use cache: 'no-store' — zero staleness on the critical data — while the static shell gives instant response. PPR is superior for pages where some data must always be fresh (buy buttons, prices, inventory) while other data can be cached (descriptions, images, reviews).
01
Explain how ISR revalidate: 60 actually works under the hood. What is the maximum staleness window?
SENIOR
02
How would you eliminate the stale window for an e-commerce product page during a flash sale?
SENIOR
03
What is the difference between ISR and PPR in terms of data freshness?
SENIOR
FAQ · 5 QUESTIONS
Frequently Asked Questions
01
Is ISR instant? When I change data in my CMS, how long until the page updates?
ISR is not instant. With time-based revalidation (revalidate: N), the page updates on the first request after the timer expires — not immediately on CMS update. With on-demand revalidation (revalidatePath/revalidateTag from a webhook), the page updates within seconds — as fast as the webhook request reaches your server and triggers regeneration. The stale window is the time between CMS update and the first regeneration request.
Was this helpful?
02
What happens to the current user during ISR regeneration?
The current user always gets the cached (possibly stale) page. ISR serves the stale page to the current request while triggering a background regeneration. The regenerated page replaces the cache for subsequent requests. This is the stale-while-revalidate pattern — the current user accepts staleness so the next user gets fresh data.
Was this helpful?
03
What is the difference between revalidate: N and on-demand revalidation?
revalidate: N is a time-based limit on regeneration frequency — the page regenerates at most once every N seconds, triggered by the first request after the timer expires. On-demand revalidation via revalidatePath or revalidateTag immediately marks the cached page as stale, regardless of the timer — the next request triggers fresh regeneration. Use revalidate: N as a fallback and on-demand revalidation as the primary mechanism.
Was this helpful?
04
Can I use ISR with dynamic routes that use cookies or headers?
No. ISR only works for routes that are statically analyzable — no dynamic APIs like cookies(), headers(), or searchParams at the page level. If you need dynamic data at the route level, use PPR: wrap the dynamic parts in Suspense boundaries with cache: 'no-store' while keeping the static shell as ISR or static.
Was this helpful?
05
How does ISR interact with generateStaticParams?
generateStaticParams defines which routes are pre-built at build time. ISR defines how those routes (and fallback routes) are regenerated after build. Routes from generateStaticParams are statically generated and then revalidated per the ISR configuration. Routes not in generateStaticParams use the fallback behavior: 'blocking' (generate on first visit), true (show loading state), or false (404).