Next.js ISR & Build Logs: diagnosing deployment failures and resolving revalidation strategy
0 reputation · 19 Sept 2024, 12:42 UTC
0 reputation · 19 Sept 2024, 12:42 UTC
Identify why a statically generated page deployed with Next.js ISR continues to serve stale content after an underlying CMS update, despite a successful build log.
The build logs show no syntax or dependency errors, yet the page’s cache headers indicate it was served from the edge without regeneration. The documented ISR feature allows a per‑page revalidate value, but the impact on edge cache invalidation when the data source changes during the revalidation window remains ambiguous. Additionally, Next.js does not expose a universal revalidation interval across all pages, raising questions about how a global setting would interact with per‑page configurations.
revalidate period expires, how does Next.js ISR determine whether to trigger a regeneration if the underlying data source has been updated?31275 reputation · 19 Sept 2024, 22:16 UTC
A clean build log tells you nothing about ISR behavior after deployment. Your build only proves the page was generated once at build time; every later regeneration happens at runtime, on the first request after the revalidate window expires. ISR is time-triggered, not data-triggered — Next.js has no way to know your CMS changed. It simply waits for the interval to elapse, then regenerates on the next incoming request and serves whatever getStaticProps fetches at that moment.
Three causes cover most cases like this:
revalidate is 3600 and the CMS updated 10 minutes ago, the stale page is correct behavior.Cache-Control override can hold a stale copy even when Next.js regenerated. This is the most common culprit when the interval has clearly passed.Request the page twice after the revalidate interval has passed and inspect the response headers:
curl -sI https://your-site.com/the-page | grep -iE 'x-nextjs-cache|cache-control|age'
x-nextjs-cache: MISS — the page was regenerated (or rendered on demand) for this request.x-nextjs-cache: STALE — the expired page was served while background regeneration ran; the next request should show fresh content.x-nextjs-cache: HIT — served from the ISR cache within the valid window.Trust x-nextjs-cache over generic Age or Cache-Control headers, since an edge platform can rewrite those. In your platform's function/runtime logs (not the build log), look for regeneration entries for the page path around the time of the request. As a final isolation step, purge the edge cache and re-request: if content updates immediately, the problem was edge-level caching, not your ISR configuration.
Next.js has no site-wide revalidate setting; each page's value in getStaticProps is independent. A common pattern is to centralize it yourself:
// lib/revalidate.js
export const REVALIDATE_SECONDS = 60;
// in each page
export async function getStaticProps() {
const data = await fetchFromCms();
return { props: { data }, revalidate: REVALIDATE_SECONDS };
}
If content must update the moment the CMS changes, time-based ISR is the wrong tool — use on-demand revalidation (res.revalidate('/the-page') from an API route triggered by a CMS webhook), which invalidates the cache immediately instead of waiting out the window.
The exact revalidate value on the affected page. If it's false, the page never regenerates after build and the fix is a config change, not cache debugging. If it's a short value (e.g., 10–60 seconds) and content is still stale after multiple requests, focus on the edge cache layer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.