Using Next.js Incremental Static Regeneration to Keep Blog Posts Fresh Without Sacrificing Speed
Learn how Next.js Incremental Static Regeneration lets you serve fast static pages while updating them in the background after a set interval, with a concrete blog‑post example and verification steps.
22 Apr 2026, 14:49 UTC

The problem: stale static pages or costly server‑side rendering
When you build a blog with Next.js, the simplest approach is to fetch data in getStaticProps and export fully static HTML. This gives you lightning‑fast page loads, but the content becomes stale as soon as a new post is published. Switching to server‑side rendering (getServerSideProps) solves the freshness issue, yet every request now hits your server (or edge function), adding latency and cost—especially for traffic spikes.
How Incremental Static Regeneration (ISR) bridges the gap
ISR lets you keep the performance benefits of static generation while updating pages in the background after a configurable time window. On the first request after the interval expires, Next.js serves the cached (stale) page immediately, then triggers a re‑validation that rebuilds the page. Subsequent visitors receive the freshly generated version until the next interval.
What happens under the hood
- A request arrives for an ISR‑enabled route.
- If the cached HTML is younger than the
revalidateseconds, it is returned instantly (cache hit). - If the cache is stale, Next.js returns the stale HTML while spawning a background process to regenerate the page.
- The regenerated HTML replaces the cache; the next request sees the fresh version.
Worked example: a blog page that updates at most once per minute
Create a dynamic route for blog posts, e.g. pages/blog/[slug].js. The page uses getStaticProps with a revalidate value of 60 seconds.
import { notFound } from 'next/navigation';
export async function generateStaticParams() {
// In a real app you would fetch the list of slugs from your CMS.
// This function runs at build time to pre‑generate known paths.
return [];
}
export async function getStaticProps({ params }) {
const { slug } = params;
const post = await fetchPostBySlug(slug); // placeholder for your data layer
if (!post) {
return { notFound: true };
}
return {
props: { post },
// Re‑generate at most once per minute.
revalidate: 60,
};
}
export default function BlogPost({ post }) {
return (
{post.title}
);
}
What you observe:
- After a new post is added to your CMS, the first visitor who arrives more than 60 seconds after the last generation sees the old post (served from cache).
- That same request triggers a background rebuild.
- The next visitor (or the same visitor after a refresh) receives the updated post.
- All subsequent visitors within the next 60‑second window get the fresh version.
Trade‑offs and limitations
- Stale‑first‑user window: The very first request after the interval may see outdated content. If your audience cannot tolerate any staleness, consider SSR or client‑side fetching for those pages.
- Server or edge requirement: Background re‑validation needs a Node.js server (or Vercel Edge Functions). A fully static export (
next export) cannot use ISR. - Unnecessary rebuilds: Setting
revalidatetoo low (e.g., 5 seconds) can cause frequent background builds, increasing load on your hosting environment.
Getting started and verifying ISR works
- Run the app in development mode:
npm run dev(oryarn dev). - Request the blog page (e.g.,
http://localhost:3000/blog/my-first-post) and note the response time. - Wait longer than the
revalidateinterval (e.g., 70 seconds). - Make a second request. You should see a quick response (served from cache) and, in the Network tab, a slight increase in latency for the subsequent request as Next.js rebuilds in the background.
- Inspect the response headers; you will find
x-nextjs-revalidate: trueon the request that triggered the background re‑validation.
If you do not see the header, ensure that you are not using next export and that your getStaticProps returns a revalidate value.
Actionable takeaway
Incremental Static Regeneration gives you a practical middle ground: near‑static performance with a bounded freshness guarantee. Use it for pages that change infrequently but must stay reasonably up‑to‑date—blog posts, product listings, or documentation. Tune the revalidate interval based on how stale your audience can tolerate, and verify the behavior with the header‑check method above. When the stale‑first‑user window is unacceptable, fall back to server‑side rendering or client‑side data fetching for those specific routes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.