How to Use Vercel ISR with Next.js Revalidate for Stale‑While‑Revalidate Static Pages
Learn how to set up Incremental Static Regeneration in Vercel, use the `revalidate` flag, test cache behavior, and avoid common pitfalls that can leave pages stale or trigger full rebuilds.
01 Feb 2026, 16:11 UTC

The Practical Problem
Static sites are fast, but they don’t update until you redeploy. If you need pages that reflect fresh data without a full rebuild, Vercel’s Incremental Static Regeneration (ISR) lets you set a revalidate interval. The key takeaway: set revalidate on a per‑page basis, test the x-vercel-cache header, and be mindful of free‑tier build minutes and cache persistence.
How ISR Works on Vercel
When a request hits a page that has a revalidate value, Vercel behaves like this:
- First request – Vercel renders the page, stores the HTML in the edge cache, and sends it to the client. The response header
x-vercel-cache: MISSindicates a fresh build. - Subsequent requests within the TTL – The cached HTML is served immediately with
x-vercel-cache: HIT. - After TTL expires – The next request still returns the old HTML (stale‑while‑revalidate) while Vercel triggers a background regeneration. Once the new build completes, the edge cache is updated for all following requests.
Vercel’s edge cache respects the Cache‑Control header you set, but by default it honors the revalidate interval you declare in your code.
Request Flow
Client → Vercel Edge → (Cache MISS) → Build → Cache HIT
│ │
└──────────────(TTL expired)───────┘
Client → Vercel Edge → (Cache HIT – stale) → Background Rebuild
│ │
└─────────────────(New HTML)──────┘
Edge Cache and Headers
Inspect the x-vercel-cache header to confirm ISR behavior. Example with curl:
curl -i https://your-project.vercel.app/faq
# Look for x-vercel-cache: MISS or HIT
Working Example
Below is a minimal Next.js page that revalidates every 30 seconds. Place this in app/page.tsx (App Router) or pages/faq.js (Pages Router).
App Router (Server Component)
// app/page.tsx
import { GetStaticPropsResult } from 'next';
export const revalidate = 30; // seconds
export default function Page() {
return FAQ – Updated every 30s;
}
Pages Router
// pages/faq.js
export async function getStaticProps() {
return {
props: {},
revalidate: 30, // seconds
};
}
export default function FAQ() {
return FAQ – Updated every 30s;
}
Deploy to Vercel. The first request will trigger a build; subsequent requests within 30 seconds come from the cache. After 30 seconds, the next request will serve stale content while a new build runs in the background.
Verification Checklist
- Deploy the page and note the URL.
- Run
curl -i https://your-project.vercel.app/faqand record thex-vercel-cacheheader. - Wait 35 seconds, run the same
curlagain. You should seeMISSon the first hit after TTL, andHITfor subsequent requests. - Check the Vercel dashboard → Deployments → Logs. Look for “ISR” or “revalidation” entries that match your
revalidateinterval. - Optional: Use the Vercel ISR Trigger API to force an immediate regeneration:
curl -X POST -H "Authorization: Bearer $VERCEL_TOKEN" \ https://api.vercel.com/v1/integrations/deployments/$DEPLOYMENT_ID/revalidate
Limitations & Common Mistakes
Free‑Tier Build Minutes
Each ISR regeneration consumes a build minute. On the free tier, frequent revalidate values (e.g., revalidate: 10) can quickly exhaust your quota. Plan the interval based on traffic and data change frequency.
Dynamic Routes & Fallbacks
For pages generated with getStaticPaths, using fallback: 'blocking' can cause a full regeneration if the path is not pre‑cached. Avoid revalidate on dynamic routes unless you handle fallback logic explicitly.
Stale Data Before TTL
If your data source updates more often than the revalidate interval, visitors may see outdated content until the next scheduled regeneration. Use the ISR Trigger API or a webhook to push a revalidation request whenever data changes.
Edge Cache Persistence
Under heavy traffic, Vercel may keep a page cached slightly longer than the TTL because the background regeneration is queued. To enforce stricter freshness, set a Cache‑Control: max-age=0, stale-while-revalidate=60 header in your page’s response.
Confusing App Router revalidate with Pages Router
In the App Router, export const revalidate applies to the entire Server Component. In the Pages Router, revalidate is part of the getStaticProps return object. Mixing the two can silently fall back to full regeneration or 404 errors on dynamic routes.
Conclusion
ISR on Vercel gives you static performance with near‑real‑time updates. By setting revalidate appropriately, testing cache headers, and respecting free‑tier limits, you can deliver fresh content without manual redeploys. Remember to monitor build minutes, use the ISR Trigger API for critical updates, and adjust Cache‑Control headers to match your freshness strategy.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.