How routeRules with isr and swr keep individual pages fresh in the background
Incremental Static Regeneration combines the delivery speed of statically generated pages with the freshness of server-rendered content, by regenerating individual pages in the background once a defined cache window expires, without needing a full rebuild of the project. This article shows how to configure ISR in Nuxt through routeRules, where the difference to SWR lies, and what a practical use case with product pages looks like.
Table of Contents
- 1. What Incremental Static Regeneration is
- 2. The difference from full SSG and classic SSR
- 3. Configuring routeRules with isr and swr
- 4. SWR versus ISR in detail
- 5. Practical use case: product pages with occasional price changes
- 6. On-demand invalidation outside the normal cache cycle
- 7. How the caching layers interact
- 8. Monitoring and common pitfalls
- 9. Decision guide: which strategy fits when
- 10. Summary
- 11. FAQ
1. What Incremental Static Regeneration is
Incremental Static Regeneration, or ISR for short, describes a rendering strategy where a page is first served exactly like an ordinary static page, but is automatically regenerated in the background once a defined time window expires and the next user requests it. The original user whose request triggered the regeneration still receives the previously cached version, while the freshly generated version only takes effect for every request that follows afterward. The concept originally comes from the Next.js ecosystem and was adopted in a similar form by Nitro, the server engine behind Nuxt.
The actual goal of ISR is to keep the delivery speed of a fully pre-rendered static page while not giving up freshness entirely. Instead of triggering a full rebuild of the entire project on every content change, which can take several minutes for thousands of pages, only the single affected page gets regenerated once its cache window has expired. That makes ISR particularly attractive for large page catalogs with occasional, but not constant, content changes.
2. The difference from full SSG and classic SSR
With Static Site Generation, or SSG, every page is fully generated as an HTML file already during the build and then served unchanged until a new build is triggered. That yields maximum delivery speed, since no server has to compute anything at request time, but has the downside that content only changes after a new, complete build, which can take an impractically long time for very large projects.
Server-Side Rendering, or SSR, is the exact opposite: every single request is rendered live on the server, so content is always maximally fresh, but at the cost of server load and response time, since actual computation happens for every request. ISR deliberately sits in between: pages are served as static HTML like with SSG, and are therefore delivered quickly, but like with SSR the content stays automatically fresh once the cache window expires, without requiring a manual rebuild.
3. Configuring routeRules with isr and swr
In Nuxt 3, rendering strategies are controlled centrally per route through the routeRules object in nuxt.config, instead of scattering configuration across individual pages in code. For true ISR with a persistent, provider-side cache, a route entry sets isr to a value in seconds, keeping in mind that true ISR in the narrow sense only works on hosting platforms that support it natively, such as Vercel or Netlify Edge, while Nitro automatically falls back to SWR-based delivery through its own cache storage on other target environments.
The example below shows a typical configuration for a shop: the homepage is fully pre-rendered at build time, product pages use ISR with a five-minute window, a particularly high-traffic promotion page uses SWR instead with a shorter window for faster updates, while the personalized account area is fully excluded from SSR and rendered on the client instead.
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/products/**': { isr: 300 },
'/products/sale/**': { swr: 60 },
'/account/**': { ssr: false },
'/api/**': { cors: true }
}
})
4. SWR versus ISR in detail
Stale-While-Revalidate, or SWR, serves the cached value from the Nitro storage of the currently running server instance first on a request, and triggers a background recomputation in parallel whose result becomes available for the next request. That cache typically lives in memory or in the configured storage driver of that particular instance and is therefore tied to its lifecycle, so with several instances running in parallel, responses can briefly differ slightly between them.
ISR in the narrow sense goes a step further and persists the regenerated page at the platform level, often directly at the CDN edge, so every instance and even every region sees the same, consistent cache state. Where that provider-side persistence does not exist, Nitro internally runs isr as SWR behavior with the same time parameter, so functionally the difference is smaller for many projects than the naming suggests, though the concrete hosting target still matters.
5. Practical use case: product pages with occasional price changes
A classic use case for ISR is product pages in an online shop: most of the content, meaning description, images, and technical specs, rarely changes, while the price gets adjusted occasionally, but not on every single request. A cache window between sixty and three hundred seconds is a good compromise for most shops, since price changes then become visible within a few minutes, while the vast majority of requests still get served from cache.
It matters to not treat the ISR window as the only safeguard, but to align it with the actual change frequency of prices: with daily price updates coming from an ERP system, a window of a few minutes is usually plenty, while flash sales with minute-precise price changes additionally need targeted, manual invalidation, described in the next section.
6. On-demand invalidation outside the normal cache cycle
Besides time-based regeneration, Nitro also supports deliberately removing individual cache entries through the storage API, so a page can be regenerated immediately after a known change instead of waiting for the cache window to expire. In practice, a webhook from the backend, for example when a new price is saved in a PIM or ERP system, triggers a dedicated, protected server route that removes the relevant cache entry via storage.removeItem.
After the entry is removed, the next incoming request for that page is automatically rendered fresh again and the cache refilled, without any user ever seeing a stale version that stayed in the cache longer than necessary. This combination of time-based ISR as a baseline safeguard and targeted, event-driven invalidation for known changes covers almost every freshness requirement in practice.
7. How the caching layers interact
In a production setup, several caching layers typically work together at the same time: Nitro's own storage driver, which can use the filesystem, Redis, or a cloud KV backend depending on the target environment, an upstream CDN layer that additionally caches HTML responses closer to the user based on cache-control headers, and the end user's browser cache itself, controlled through the same or additional headers.
For ISR to behave as expected, these layers need to be aligned: a CDN that caches HTML responses longer than the configured ISR window would effectively defeat the regeneration, because requests would never even reach the Nitro server. In practice it is worth deliberately checking the header configuration of the given hosting provider, instead of blindly relying on default settings.
8. Monitoring and common pitfalls
A common pitfall is the so-called cache stampede: if the cache window for a very popular page expires and many simultaneous requests arrive shortly after, several regenerations could start in parallel without proper safeguards and put unnecessary load on the server. Modern Nitro versions mitigate this through internal locking mechanisms, but for very high-traffic pages it is still worth checking actual behavior under load rather than relying purely on theory.
It is equally important to test ISR behavior realistically in a preview or staging environment, since hosting providers can differ in the details, and behavior tested locally in dev mode does not necessarily map one to one onto the production environment. A short manual check after every deployment, deliberately watching a page with a known cache window, catches such discrepancies early.
9. Decision guide: which strategy fits when
For content that practically never changes, such as finished blog posts or legal pages, full prerendering at build time remains the simplest and fastest solution. For content with occasional but predictable changes, such as product prices or stock levels, ISR is the natural middle ground, while for heavily personalized or security-sensitive areas such as a logged-in account section, classic SSR or even pure client-side rendering remains the right choice.
In practice, most larger Nuxt projects combine all three strategies within the same application, controlled through exactly the routeRules object shown in this article. That route-level granularity is ultimately the biggest advantage over committing an entire project to a single rendering strategy.
| Strategy | Generation | Update behavior | Typical use case |
|---|---|---|---|
| SSG (prerender) | Fully at build time | Only through a new build | Landing pages, finished blog posts |
| SSR | Live on every request | Always fresh, higher server load | Personalized, highly dynamic content |
| SWR | Cached, revalidated in the background | Next request after expiry triggers a refresh | Frequently visited, fairly stable pages |
| ISR | Cached, persisted at the provider level | Background regeneration after the window expires | Product pages with occasional price changes |
Mironsoft
Vue architecture, Composition API, and Nuxt performance
Vue applications that don't get more complicated with every feature?
We review existing Vue and Nuxt projects for unstructured composables, unnecessary reactivity, and bloated bundles, then build an architecture that absorbs new features without making the codebase harder to follow.
Architecture Review
Checking composables, state management, and component structure for maintainability.
Performance Audit
Systematically optimizing reactivity overhead, bundle size, and Nuxt rendering strategy.
Nuxt Integration
Building robust, type-safe SSR/SSG setup and API integration.
10. Summary
ISR in Nuxt at a Glance
Concept
Served statically, regenerated in the background once a time window expires.
Configuration
routeRules with isr: seconds or swr: seconds inside nuxt.config.
Requirement
True ISR needs provider-side support, otherwise it falls back to SWR.
Use case
Product pages and similar content with occasional changes.