Nuxt Route Rules for Hybrid Rendering
This guide is part of Vue & Nuxt Performance, within Framework Performance. By default, a Nuxt app server-renders every route on every request. That is flexible but wasteful: a pricing page that changes monthly, a blog post that never changes, and a product page that changes hourly all pay the full cost of rendering per request, and users pay it in TTFB. Route rules let you choose per route pattern: prerender at build time, cache with stale-while-revalidate, regenerate incrementally, render only on the client, or keep full SSR — along with headers, redirects and CORS.
Choosing well is the single largest TTFB lever in most Nuxt apps. Static and cached routes are served from the CDN or Nitro's cache in milliseconds; only routes that truly need per-request rendering pay for it.
Rapid Diagnosis
- List routes and how often their content changes: build-time, hourly, per request, per user.
- Check current rendering: are all routes SSR on every request?
- Check TTFB per route in the field.
- Check hosting: whether the platform supports Nitro's cache, ISR or CDN caching for route rules.
Root Cause Analysis
1. Default SSR everywhere. Every request renders.
2. No caching of rendered HTML. Even unchanged pages are rebuilt.
3. Personalisation assumptions. Pages treated as personalised when only a small part is.
4. Dashboards rendered on the server. Private, interactive pages with no SEO need incur SSR cost.
Step-by-Step Resolution
1. Define route rules
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/pricing': { prerender: true },
'/blog/**': { swr: 3600 }, // cached, revalidated hourly in the background
'/products/**': { swr: 600 },
'/search': { swr: 60 },
'/account/**': { ssr: false }, // client-only dashboard
'/api/catalog/**': { cache: { maxAge: 300 } },
},
});
// trade-off: SWR serves possibly stale content for up to the TTL; choose TTLs per
// route based on how quickly changes must appear.
2. Separate personal parts from cacheable pages
Render shared content in cached routes and fetch personal parts (cart count, greeting) on the client after hydration, so the route itself can be cached.
3. Match rules to hosting
On platforms with ISR support, isr uses the platform's CDN caching; on Node servers, swr uses Nitro's cache storage. Check the deployment preset's documentation.
4. Purge or revalidate on content changes
Trigger rebuilds or cache invalidation from the CMS when content changes, so long TTLs do not mean stale content.
Verification
Check response headers and timing for each route type: prerendered pages served statically, SWR routes showing cache hits after the first request, client-only routes returning a shell. Measure TTFB per route in the field. Verify freshness: update content and confirm it appears within the expected time.
Worked Example: A Software Vendor's Website
A software vendor's Nuxt site served marketing pages, docs, a blog, a changelog and a customer portal — all SSR on every request from a single-region Node server. TTFB p75 was 700ms globally. The team prerendered marketing pages, cached docs and blog with swr: 3600 (with a CMS webhook to purge on publish), cached the changelog for 10 minutes, and made the customer portal client-only. TTFB p75 for public pages fell to 90ms, server CPU dropped by 85%, and LCP p75 improved from 2.6 to 1.5 seconds. The portal's LCP was unchanged, but its server load disappeared.
Hybrid Rendering and Personalisation
Many pages that seem personalised are mostly shared: a product page with a personalised price for logged-in users, a homepage with a greeting. Cache the shared page and fetch personal data client-side (with skeleton placeholders sized to avoid CLS), or use edge logic to vary the cache by a small set of segments (currency, country). This keeps pages cacheable while still showing personal content. Avoid varying the cache by session cookie, which destroys the hit rate.
Monitoring Cache Effectiveness
Route rules only help if the cache is hit. Expose a cache status (for example, a Server-Timing entry or response header added by the platform) and track hit ratio per route group. Low hit ratios on SWR routes usually mean the cache key varies too much (query parameters, cookies) or TTLs are too short for the traffic level. Pages with little traffic will miss more often; prerendering popular ones at build time and using SWR for the rest balances build time and freshness.
Rolling Out Route Rules
Introduce route rules gradually, starting with the routes whose content changes least: legal pages, marketing pages and documentation. Prerender them and confirm they deploy correctly. Next, add SWR caching to blog and product routes with a conservative TTL and a purge mechanism, and watch for stale-content reports. Finally, consider client-only rendering for private areas. Keep the route rules file commented with the reason for each rule, since future changes to content or personalisation may require revisiting them. Review the rules whenever a new section of the site is added.
Common Mistakes
- SSR for static pages. Wasted server time and slower TTFB.
- Caching personalised pages. Users see each other's data.
- Very long TTLs without purging. Content changes take hours to appear.
- Client-only rendering for public pages. Hurts LCP and SEO.
Edge Cases
Prerendering many pages. Large sites may prefer SWR for low-traffic pages to keep builds fast.
Query parameters. Decide whether cached routes vary by query; normalise or ignore irrelevant parameters.
Preview mode. Bypass caches for editors previewing unpublished content.
API caching. Cache API routes used by many pages, which also speeds up client navigations.
FAQ
What are Nuxt route rules?
A configuration object mapping route patterns to rendering and caching options, headers, redirects and more.
What is the difference between swr and isr?
Both cache rendered pages and refresh them. swr uses Nitro's cache (server storage); isr relies on platform CDN support where available.
Does ssr: false hurt SEO?
Yes for public pages, because the initial HTML lacks content. Use it for private, app-like routes.
Can I prerender dynamic routes?
Yes, by listing them or letting the crawler discover links at build time. For very many pages, combine with SWR.
How do I invalidate cached routes?
Redeploy for prerendered routes, or clear Nitro's cache storage or the platform cache for SWR/ISR routes, often from a CMS webhook.
Do route rules affect client-side navigation?
They affect what the server returns. Client navigations fetch payloads, which can be cached and prerendered too.
Can route rules set cache headers?
Yes, with the headers option, for example to add Cache-Control for static assets or API routes.
Should every page be prerendered?
Only if content is known at build time and builds stay fast. Use SWR or ISR for frequently updated or very numerous pages.
Can route rules apply to API routes?
Yes. Cache rules on server API routes speed up both server rendering and client-side data fetching.
Do route rules work with static hosting?
Prerendered routes do. SWR and server rendering need a server or a platform that supports Nitro's server output.
Related
- Fixing TTFB from serverless cold starts — another reason to cache routes.
- Cache-Control for HTML documents — HTTP caching for pages.
- Next.js partial prerendering — a similar hybrid idea in Next.js.