ISR Build Time Reduction: From Minutes to Seconds
Stop pre-rendering 500 pages at build time—use ISR to generate on-demand and cut deploys from minutes to seconds.
Your Next.js build takes 5 minutes because it's pre-rendering 500 pages. Switch to ISR with
fallback: 'blocking' and watch it drop to under a minute—pages generate on
first request instead of during deployment.
The Build Time Trap
Static Site Generation (SSG) renders every page at build time. For content-heavy sites, this becomes painful quickly:
// 500 blog posts × ~200ms each = 100 seconds just for posts
export async function getStaticPaths() {
const posts = await getAllPosts(); // 500 posts
return {
paths: posts.map(p => ({ params: { slug: p.slug } })),
fallback: false // ← Forces ALL pages to build upfront
};
}Every deployment waits for every page. Add product pages, user profiles, or documentation, and you're looking at 10+ minute builds that destroy iteration speed.
ISR: Build Zero, Generate On-Demand
Incremental Static Regeneration flips the model. Return empty paths and let pages generate when visitors request them:
export async function getStaticPaths() {
return {
paths: [], // ← Build nothing upfront
fallback: 'blocking' // ← Generate on first request
};
}
export async function getStaticProps({ params }) {
const post = await getPost(params.slug);
return {
props: { post },
revalidate: 3600 // Cache for 1 hour, then regenerate
};
}Build time: near-zero. First visitor waits for generation (~200ms), everyone after gets the cached static page instantly.
Hybrid: Critical Pages Only
Don't want cold-start latency on your top pages? Pre-render the important ones:
export async function getStaticPaths() {
// Only pre-render top 20 posts
const topPosts = await getTopPosts(20);
return {
paths: topPosts.map(p => ({ params: { slug: p.slug } })),
fallback: 'blocking' // Rest generate on-demand
};
}Your homepage, top content, and landing pages are instant. Long-tail content generates when needed—no build time cost.
Production-Only Pre-rendering
Another pattern: skip pre-rendering entirely in preview deployments:
export async function getStaticPaths() {
// Fast previews, full builds only for production
if (process.env.VERCEL_ENV !== 'production') {
return { paths: [], fallback: 'blocking' };
}
const posts = await getAllPosts();
return {
paths: posts.map(p => ({ params: { slug: p.slug } })),
fallback: 'blocking'
};
}Preview deploys finish in seconds. Production builds take longer but run less frequently and have full static coverage.
App Router: generateStaticParams
Same principle applies in the App Router with generateStaticParams:
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
// Return empty for on-demand generation
return [];
}
// Enable ISR
export const revalidate = 3600;
Or use dynamicParams = true (default) with partial static params
for the hybrid approach.
When NOT to Use ISR
- SEO-critical pages: Pre-render so crawlers never hit cold cache
- Time-sensitive content: Revalidation delay might show stale data
- Authenticated pages: Use SSR or client-side fetching instead
- High-traffic launches: Pre-warm cache to avoid thundering herd
The Numbers
Real-world impact from a 500-page blog migration:
- Before (SSG all): 4.5 minute builds
- After (ISR + top 50): 45 second builds
- First-visit latency: ~300ms (acceptable for long-tail content)
- Subsequent visits: Identical to full SSG
The developer experience improvement alone is worth it. Fast feedback loops mean more iterations and better code.
Advertisement
Explore these curated resources to deepen your understanding
Official Documentation
Tools & Utilities
Related Insights
Explore related edge cases and patterns
Advertisement