[{"data":1,"prerenderedAt":981},["ShallowReactive",2],{"content:\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering":3,"surroundings:\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering":972},{"id":4,"title":5,"body":6,"description":952,"extension":953,"meta":954,"navigation":965,"path":966,"seo":967,"stem":970,"__hash__":971},"content\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering\u002Findex.md","Nuxt Route Rules for Hybrid Rendering",{"type":7,"value":8,"toc":933},"minimark",[9,13,33,36,125,130,158,162,168,174,180,186,190,195,375,379,382,386,397,401,404,549,553,556,560,567,571,574,578,585,715,719,722,726,752,756,762,768,774,780,784,796,811,820,829,838,847,864,873,882,891,895,918,923,926,929],[10,11,5],"h1",{"id":12},"nuxt-route-rules-for-hybrid-rendering",[14,15,16,17,22,23,27,28,32],"p",{},"This guide is part of ",[18,19,21],"a",{"href":20},"\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002F","Vue & Nuxt Performance",", within ",[18,24,26],{"href":25},"\u002Fframework-performance\u002F","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. ",[29,30,31],"strong",{},"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.",[14,34,35],{},"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.",[14,37,38],{},[39,40,46,47,46,54,46,58,46,61,46,70,46,76,46,83,46,91,46,96,46,100,46,106,46,110,46,114,46,121,46],"svg",{"viewBox":41,"width":42,"role":43,"ariaLabel":44,"style":45},"0 0 760 163","100%","img","Bar chart comparing TTFB at the 75th percentile for a blog post served with different Nuxt route rules.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[48,49],"rect",{"className":50,"x":52,"y":52,"width":42,"height":42,"fill":53},[51],"svg-canvas","0","#ffffff",[55,56,57],"title",{},"TTFB p75 by route rule (same blog post template)",[59,60,44],"desc",{},[48,62],{"x":63,"y":63,"width":64,"height":65,"rx":66,"fill":67,"stroke":68,"style":69},"1","758","161","10","none","currentColor","stroke-opacity:0.18",[71,72,57],"text",{"x":73,"y":74,"fill":68,"style":75},"28.0","34.0","font-size:16px;font-weight:700",[71,77,82],{"x":78,"y":79,"fill":68,"style":80,"textAnchor":81},"162.5","70.0","font-size:13px","end","SSR every request",[48,84],{"x":85,"y":86,"width":87,"height":88,"rx":89,"fill":67,"stroke":68,"style":90},"174.5","56.0","493.5","19","3","fill-opacity:0.7;stroke-opacity:0.35",[71,92,95],{"x":93,"y":79,"fill":68,"style":94},"674.0","font-size:12px;font-weight:600","640ms",[71,97,99],{"x":78,"y":98,"fill":68,"style":80,"textAnchor":81},"101.0","swr: 3600 (Nitro cache)",[48,101],{"x":85,"y":102,"width":103,"height":88,"rx":89,"fill":104,"stroke":104,"style":105},"87.0","107.9","#0466c8","fill-opacity:0.55;stroke-opacity:0.9",[71,107,109],{"x":108,"y":98,"fill":68,"style":94},"288.5","140ms",[71,111,113],{"x":78,"y":112,"fill":68,"style":80,"textAnchor":81},"132.0","prerender: true (CDN)",[48,115],{"x":85,"y":116,"width":117,"height":88,"rx":89,"fill":118,"stroke":119,"style":120},"118.0","46.3","#ffc300","#b8860b","fill-opacity:0.7;stroke-opacity:0.9",[71,122,124],{"x":123,"y":112,"fill":68,"style":94},"226.8","60ms",[126,127,129],"h2",{"id":128},"rapid-diagnosis","Rapid Diagnosis",[131,132,133,140,146,152],"ul",{},[134,135,136,139],"li",{},[29,137,138],{},"List routes and how often their content changes",": build-time, hourly, per request, per user.",[134,141,142,145],{},[29,143,144],{},"Check current rendering",": are all routes SSR on every request?",[134,147,148,151],{},[29,149,150],{},"Check TTFB per route"," in the field.",[134,153,154,157],{},[29,155,156],{},"Check hosting",": whether the platform supports Nitro's cache, ISR or CDN caching for route rules.",[126,159,161],{"id":160},"root-cause-analysis","Root Cause Analysis",[14,163,164,167],{},[29,165,166],{},"1. Default SSR everywhere."," Every request renders.",[14,169,170,173],{},[29,171,172],{},"2. No caching of rendered HTML."," Even unchanged pages are rebuilt.",[14,175,176,179],{},[29,177,178],{},"3. Personalisation assumptions."," Pages treated as personalised when only a small part is.",[14,181,182,185],{},[29,183,184],{},"4. Dashboards rendered on the server."," Private, interactive pages with no SEO need incur SSR cost.",[126,187,189],{"id":188},"step-by-step-resolution","Step-by-Step Resolution",[191,192,194],"h3",{"id":193},"_1-define-route-rules","1. Define route rules",[196,197,202],"pre",{"className":198,"code":199,"language":200,"meta":201,"style":201},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  routeRules: {\n    '\u002F': { prerender: true },\n    '\u002Fpricing': { prerender: true },\n    '\u002Fblog\u002F**': { swr: 3600 },                    \u002F\u002F cached, revalidated hourly in the background\n    '\u002Fproducts\u002F**': { swr: 600 },\n    '\u002Fsearch': { swr: 60 },\n    '\u002Faccount\u002F**': { ssr: false },                \u002F\u002F client-only dashboard\n    '\u002Fapi\u002Fcatalog\u002F**': { cache: { maxAge: 300 } },\n  },\n});\n\u002F\u002F trade-off: SWR serves possibly stale content for up to the TTL; choose TTLs per\n\u002F\u002F route based on how quickly changes must appear.\n","javascript","",[203,204,205,214,232,239,256,268,286,299,312,330,345,354,363,369],"code",{"__ignoreMap":201},[206,207,210],"span",{"class":208,"line":209},"line",1,[206,211,213],{"class":212},"sjfSM","\u002F\u002F nuxt.config.ts\n",[206,215,217,221,224,228],{"class":208,"line":216},2,[206,218,220],{"class":219},"sPARh","export",[206,222,223],{"class":219}," default",[206,225,227],{"class":226},"smZ65"," defineNuxtConfig",[206,229,231],{"class":230},"sQw3B","({\n",[206,233,235],{"class":208,"line":234},3,[206,236,238],{"class":237},"saISM","  routeRules: {\n",[206,240,242,246,249,253],{"class":208,"line":241},4,[206,243,245],{"class":244},"sZ8jY","    '\u002F'",[206,247,248],{"class":237},": { prerender: ",[206,250,252],{"class":251},"sPXB4","true",[206,254,255],{"class":237}," },\n",[206,257,259,262,264,266],{"class":208,"line":258},5,[206,260,261],{"class":244},"    '\u002Fpricing'",[206,263,248],{"class":237},[206,265,252],{"class":251},[206,267,255],{"class":237},[206,269,271,274,277,280,283],{"class":208,"line":270},6,[206,272,273],{"class":244},"    '\u002Fblog\u002F**'",[206,275,276],{"class":237},": { swr: ",[206,278,279],{"class":251},"3600",[206,281,282],{"class":237}," },                    ",[206,284,285],{"class":212},"\u002F\u002F cached, revalidated hourly in the background\n",[206,287,289,292,294,297],{"class":208,"line":288},7,[206,290,291],{"class":244},"    '\u002Fproducts\u002F**'",[206,293,276],{"class":237},[206,295,296],{"class":251},"600",[206,298,255],{"class":237},[206,300,302,305,307,310],{"class":208,"line":301},8,[206,303,304],{"class":244},"    '\u002Fsearch'",[206,306,276],{"class":237},[206,308,309],{"class":251},"60",[206,311,255],{"class":237},[206,313,315,318,321,324,327],{"class":208,"line":314},9,[206,316,317],{"class":244},"    '\u002Faccount\u002F**'",[206,319,320],{"class":237},": { ssr: ",[206,322,323],{"class":251},"false",[206,325,326],{"class":237}," },                ",[206,328,329],{"class":212},"\u002F\u002F client-only dashboard\n",[206,331,333,336,339,342],{"class":208,"line":332},10,[206,334,335],{"class":244},"    '\u002Fapi\u002Fcatalog\u002F**'",[206,337,338],{"class":237},": { cache: { maxAge: ",[206,340,341],{"class":251},"300",[206,343,344],{"class":237}," } },\n",[206,346,348,351],{"class":208,"line":347},11,[206,349,350],{"class":237},"  }",[206,352,353],{"class":230},",\n",[206,355,357,360],{"class":208,"line":356},12,[206,358,359],{"class":230},"})",[206,361,362],{"class":237},";\n",[206,364,366],{"class":208,"line":365},13,[206,367,368],{"class":212},"\u002F\u002F trade-off: SWR serves possibly stale content for up to the TTL; choose TTLs per\n",[206,370,372],{"class":208,"line":371},14,[206,373,374],{"class":212},"\u002F\u002F route based on how quickly changes must appear.\n",[191,376,378],{"id":377},"_2-separate-personal-parts-from-cacheable-pages","2. Separate personal parts from cacheable pages",[14,380,381],{},"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.",[191,383,385],{"id":384},"_3-match-rules-to-hosting","3. Match rules to hosting",[14,387,388,389,392,393,396],{},"On platforms with ISR support, ",[203,390,391],{},"isr"," uses the platform's CDN caching; on Node servers, ",[203,394,395],{},"swr"," uses Nitro's cache storage. Check the deployment preset's documentation.",[191,398,400],{"id":399},"_4-purge-or-revalidate-on-content-changes","4. Purge or revalidate on content changes",[14,402,403],{},"Trigger rebuilds or cache invalidation from the CMS when content changes, so long TTLs do not mean stale content.",[14,405,406],{},[39,407,46,410,46,413,46,416,46,418,46,435,46,438,46,440,46,446,46,453,46,457,46,462,46,470,46,476,46,480,46,486,46,489,46,493,46,496,46,499,46,502,46,505,46,508,46,511,46,515,46,519,46,523,46,525,46,529,46,532,46,535,46,539,46,542,46,545,46],{"viewBox":408,"width":42,"role":43,"ariaLabel":409,"style":45},"0 0 760 342","Decision sequence for selecting a Nuxt route rule for a route.",[48,411],{"className":412,"x":52,"y":52,"width":42,"height":42,"fill":53},[51],[55,414,415],{},"Choosing a route rule",[59,417,409],{},[419,420,421],"defs",{},[422,423,430],"marker",{"id":424,"viewBox":425,"refX":426,"refY":427,"markerWidth":428,"markerHeight":428,"orient":429},"facca94064","0 0 10 10","9","5","7","auto-start-reverse",[431,432],"path",{"d":433,"fill":68,"style":434},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[48,436],{"x":63,"y":63,"width":64,"height":437,"rx":66,"fill":67,"stroke":68,"style":69},"340",[71,439,415],{"x":73,"y":74,"fill":68,"style":75},[48,441],{"x":73,"y":86,"width":442,"height":443,"rx":444,"fill":68,"stroke":68,"style":445},"320.0","35.0","6","fill-opacity:0.06;stroke-opacity:0.4",[71,447,452],{"x":448,"y":449,"fill":68,"style":450,"textAnchor":451},"188.0","78.0","font-size:13px;font-weight:700","middle","Does content change only on deploy?",[48,454],{"x":455,"y":86,"width":442,"height":443,"rx":444,"fill":118,"stroke":119,"style":456},"412.0","fill-opacity:0.24;stroke-opacity:0.9",[71,458,461],{"x":459,"y":449,"fill":68,"style":460,"textAnchor":451},"572.0","font-size:12.5px","prerender: true",[208,463],{"x1":464,"y1":465,"x2":466,"y2":465,"stroke":68,"strokeWidth":467,"style":468,"markerEnd":469},"348.0","73.5","410.0","1.5","stroke-opacity:0.6","url(#facca94064)",[71,471,475],{"x":472,"y":473,"fill":104,"style":474,"textAnchor":451},"380.0","66.5","font-size:11.5px;font-weight:700","yes",[208,477],{"x1":448,"y1":478,"x2":448,"y2":479,"stroke":68,"strokeWidth":467,"style":468,"markerEnd":469},"91.0","125.0",[71,481,485],{"x":482,"y":483,"fill":484,"style":474},"196.0","113.0","#51617a","no",[48,487],{"x":73,"y":488,"width":442,"height":443,"rx":444,"fill":68,"stroke":68,"style":445},"127.0",[71,490,492],{"x":448,"y":491,"fill":68,"style":450,"textAnchor":451},"149.0","Is content shared but updated over time?",[48,494],{"x":455,"y":488,"width":442,"height":443,"rx":444,"fill":104,"stroke":104,"style":495},"fill-opacity:0.14;stroke-opacity:0.9",[71,497,498],{"x":459,"y":491,"fill":68,"style":460,"textAnchor":451},"swr or isr with a TTL",[208,500],{"x1":464,"y1":501,"x2":466,"y2":501,"stroke":68,"strokeWidth":467,"style":468,"markerEnd":469},"144.5",[71,503,475],{"x":472,"y":504,"fill":104,"style":474,"textAnchor":451},"137.5",[208,506],{"x1":448,"y1":507,"x2":448,"y2":482,"stroke":68,"strokeWidth":467,"style":468,"markerEnd":469},"162.0",[71,509,485],{"x":482,"y":510,"fill":484,"style":474},"184.0",[48,512],{"x":73,"y":513,"width":442,"height":514,"rx":444,"fill":68,"stroke":68,"style":445},"198.0","52.0",[71,516,518],{"x":448,"y":517,"fill":68,"style":450,"textAnchor":451},"220.0","Is the page private and interactive, without SEO",[71,520,522],{"x":448,"y":521,"fill":68,"style":450,"textAnchor":451},"237.0","needs?",[48,524],{"x":455,"y":513,"width":442,"height":514,"rx":444,"fill":104,"stroke":104,"style":495},[71,526,528],{"x":459,"y":527,"fill":68,"style":460,"textAnchor":451},"228.5","ssr: false",[208,530],{"x1":464,"y1":531,"x2":466,"y2":531,"stroke":68,"strokeWidth":467,"style":468,"markerEnd":469},"224.0",[71,533,475],{"x":472,"y":534,"fill":104,"style":474,"textAnchor":451},"217.0",[208,536],{"x1":448,"y1":537,"x2":448,"y2":538,"stroke":68,"strokeWidth":467,"style":468,"markerEnd":469},"250.0","284.0",[71,540,485],{"x":482,"y":541,"fill":484,"style":474},"272.0",[48,543],{"x":73,"y":544,"width":442,"height":74,"rx":444,"fill":118,"stroke":119,"style":456},"286.0",[71,546,548],{"x":448,"y":547,"fill":68,"style":460,"textAnchor":451},"307.5","SSR per request (keep it fast, stream if possible)",[126,550,552],{"id":551},"verification","Verification",[14,554,555],{},"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.",[126,557,559],{"id":558},"worked-example-a-software-vendors-website","Worked Example: A Software Vendor's Website",[14,561,562,563,566],{},"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 ",[203,564,565],{},"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.",[126,568,570],{"id":569},"hybrid-rendering-and-personalisation","Hybrid Rendering and Personalisation",[14,572,573],{},"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.",[126,575,577],{"id":576},"monitoring-cache-effectiveness","Monitoring Cache Effectiveness",[14,579,580,581,584],{},"Route rules only help if the cache is hit. Expose a cache status (for example, a ",[203,582,583],{},"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.",[14,586,587],{},[39,588,46,591,46,594,46,597,46,599,46,602,46,604,46,608,46,615,46,619,46,623,46,626,46,630,46,634,46,637,46,639,46,643,46,645,46,648,46,651,46,655,46,657,46,660,46,662,46,665,46,668,46,672,46,674,46,677,46,679,46,682,46,685,46,688,46,690,46,693,46,695,46,698,46,701,46,705,46,707,46,710,46,712,46],{"viewBox":589,"width":42,"role":43,"ariaLabel":590,"style":45},"0 0 760 258","The main Nuxt route rule options and what they do.",[48,592],{"className":593,"x":52,"y":52,"width":42,"height":42,"fill":53},[51],[55,595,596],{},"Route rule options at a glance",[59,598,590],{},[48,600],{"x":63,"y":63,"width":64,"height":601,"rx":66,"fill":67,"stroke":68,"style":69},"256",[71,603,596],{"x":73,"y":74,"fill":68,"style":75},[48,605],{"x":73,"y":86,"width":606,"height":607,"rx":52,"fill":68,"stroke":68,"style":445},"106.3","30.0",[71,609,614],{"x":610,"y":611,"fill":68,"style":612,"textAnchor":613},"38.0","75.5","font-size:12.5px;font-weight:700","start","Option",[48,616],{"x":617,"y":86,"width":618,"height":607,"rx":52,"fill":68,"stroke":68,"style":445},"134.3","298.9",[71,620,622],{"x":621,"y":611,"fill":68,"style":612,"textAnchor":451},"283.7","Where HTML comes from",[48,624],{"x":625,"y":86,"width":618,"height":607,"rx":52,"fill":68,"stroke":68,"style":445},"433.1",[71,627,629],{"x":628,"y":611,"fill":68,"style":612,"textAnchor":451},"582.6","Freshness",[48,631],{"x":73,"y":632,"width":606,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},"86.0","stroke-opacity:0.35",[71,635,461],{"x":610,"y":636,"fill":68,"style":612,"textAnchor":613},"105.5",[48,638],{"x":617,"y":632,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,640,642],{"x":621,"y":636,"fill":68,"style":641,"textAnchor":451},"font-size:12px","build output (static)",[48,644],{"x":625,"y":632,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,646,647],{"x":628,"y":636,"fill":68,"style":641,"textAnchor":451},"until next deploy",[48,649],{"x":73,"y":650,"width":606,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},"116.0",[71,652,654],{"x":610,"y":653,"fill":68,"style":612,"textAnchor":613},"135.5","swr: N",[48,656],{"x":617,"y":650,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,658,659],{"x":621,"y":653,"fill":68,"style":641,"textAnchor":451},"Nitro cache",[48,661],{"x":625,"y":650,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,663,664],{"x":628,"y":653,"fill":68,"style":641,"textAnchor":451},"refreshed in background after N s",[48,666],{"x":73,"y":667,"width":606,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},"146.0",[71,669,671],{"x":610,"y":670,"fill":68,"style":612,"textAnchor":613},"165.5","isr: N",[48,673],{"x":617,"y":667,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,675,676],{"x":621,"y":670,"fill":68,"style":641,"textAnchor":451},"platform CDN cache",[48,678],{"x":625,"y":667,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,680,681],{"x":628,"y":670,"fill":68,"style":641,"textAnchor":451},"refreshed after N s",[48,683],{"x":73,"y":684,"width":606,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},"176.0",[71,686,528],{"x":610,"y":687,"fill":68,"style":612,"textAnchor":613},"195.5",[48,689],{"x":617,"y":684,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,691,692],{"x":621,"y":687,"fill":68,"style":641,"textAnchor":451},"client renders a shell",[48,694],{"x":625,"y":684,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,696,697],{"x":628,"y":687,"fill":68,"style":641,"textAnchor":451},"always live data",[48,699],{"x":73,"y":700,"width":606,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},"206.0",[71,702,704],{"x":610,"y":703,"fill":68,"style":612,"textAnchor":613},"225.5","default SSR",[48,706],{"x":617,"y":700,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,708,709],{"x":621,"y":703,"fill":68,"style":641,"textAnchor":451},"rendered per request",[48,711],{"x":625,"y":700,"width":618,"height":607,"rx":52,"fill":67,"stroke":68,"style":633},[71,713,714],{"x":628,"y":703,"fill":68,"style":641,"textAnchor":451},"always fresh",[126,716,718],{"id":717},"rolling-out-route-rules","Rolling Out Route Rules",[14,720,721],{},"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.",[126,723,725],{"id":724},"common-mistakes","Common Mistakes",[131,727,728,734,740,746],{},[134,729,730,733],{},[29,731,732],{},"SSR for static pages."," Wasted server time and slower TTFB.",[134,735,736,739],{},[29,737,738],{},"Caching personalised pages."," Users see each other's data.",[134,741,742,745],{},[29,743,744],{},"Very long TTLs without purging."," Content changes take hours to appear.",[134,747,748,751],{},[29,749,750],{},"Client-only rendering for public pages."," Hurts LCP and SEO.",[126,753,755],{"id":754},"edge-cases","Edge Cases",[14,757,758,761],{},[29,759,760],{},"Prerendering many pages."," Large sites may prefer SWR for low-traffic pages to keep builds fast.",[14,763,764,767],{},[29,765,766],{},"Query parameters."," Decide whether cached routes vary by query; normalise or ignore irrelevant parameters.",[14,769,770,773],{},[29,771,772],{},"Preview mode."," Bypass caches for editors previewing unpublished content.",[14,775,776,779],{},[29,777,778],{},"API caching."," Cache API routes used by many pages, which also speeds up client navigations.",[126,781,783],{"id":782},"faq","FAQ",[785,786,789,793],"details",{"className":787},[788],"faq-item",[790,791,792],"summary",{},"What are Nuxt route rules?",[14,794,795],{},"A configuration object mapping route patterns to rendering and caching options, headers, redirects and more.",[785,797,799,802],{"className":798},[788],[790,800,801],{},"What is the difference between swr and isr?",[14,803,804,805,807,808,810],{},"Both cache rendered pages and refresh them. ",[203,806,395],{}," uses Nitro's cache (server storage); ",[203,809,391],{}," relies on platform CDN support where available.",[785,812,814,817],{"className":813},[788],[790,815,816],{},"Does ssr: false hurt SEO?",[14,818,819],{},"Yes for public pages, because the initial HTML lacks content. Use it for private, app-like routes.",[785,821,823,826],{"className":822},[788],[790,824,825],{},"Can I prerender dynamic routes?",[14,827,828],{},"Yes, by listing them or letting the crawler discover links at build time. For very many pages, combine with SWR.",[785,830,832,835],{"className":831},[788],[790,833,834],{},"How do I invalidate cached routes?",[14,836,837],{},"Redeploy for prerendered routes, or clear Nitro's cache storage or the platform cache for SWR\u002FISR routes, often from a CMS webhook.",[785,839,841,844],{"className":840},[788],[790,842,843],{},"Do route rules affect client-side navigation?",[14,845,846],{},"They affect what the server returns. Client navigations fetch payloads, which can be cached and prerendered too.",[785,848,850,853],{"className":849},[788],[790,851,852],{},"Can route rules set cache headers?",[14,854,855,856,859,860,863],{},"Yes, with the ",[203,857,858],{},"headers"," option, for example to add ",[203,861,862],{},"Cache-Control"," for static assets or API routes.",[785,865,867,870],{"className":866},[788],[790,868,869],{},"Should every page be prerendered?",[14,871,872],{},"Only if content is known at build time and builds stay fast. Use SWR or ISR for frequently updated or very numerous pages.",[785,874,876,879],{"className":875},[788],[790,877,878],{},"Can route rules apply to API routes?",[14,880,881],{},"Yes. Cache rules on server API routes speed up both server rendering and client-side data fetching.",[785,883,885,888],{"className":884},[788],[790,886,887],{},"Do route rules work with static hosting?",[14,889,890],{},"Prerendered routes do. SWR and server rendering need a server or a platform that supports Nitro's server output.",[126,892,894],{"id":893},"related","Related",[131,896,897,904,911],{},[134,898,899,903],{},[18,900,902],{"href":901},"\u002Fnetwork-protocol-optimization\u002Ftime-to-first-byte-optimization\u002Ffixing-ttfb-from-serverless-cold-starts\u002F","Fixing TTFB from serverless cold starts"," — another reason to cache routes.",[134,905,906,910],{},[18,907,909],{"href":908},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fhttp-cache-control-headers-explained\u002Fcache-control-for-html-documents\u002F","Cache-Control for HTML documents"," — HTTP caching for pages.",[134,912,913,917],{},[18,914,916],{"href":915},"\u002Fframework-performance\u002Fnextjs-performance\u002Fnextjs-partial-prerendering\u002F","Next.js partial prerendering"," — a similar hybrid idea in Next.js.",[919,920,922],"script",{"type":921},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Nuxt Route Rules for Hybrid Rendering\",\n  \"description\": \"How to assign the right rendering and caching mode to each route in Nuxt, and how route rules affect TTFB, freshness and server cost.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Define route rules\",\n      \"text\": \"Define route rules\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Separate personal parts from cacheable pages\",\n      \"text\": \"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.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Match rules to hosting\",\n      \"text\": \"On platforms with ISR support, isr uses the platform's CDN caching; on Node servers, swr uses Nitro's cache storage.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Purge or revalidate on content changes\",\n      \"text\": \"Trigger rebuilds or cache invalidation from the CMS when content changes, so long TTLs do not mean stale content.\"\n    }\n  ]\n}\n",[919,924,925],{"type":921},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Nuxt Route Rules for Hybrid Rendering\",\n  \"description\": \"How to assign the right rendering and caching mode to each route in Nuxt, and how route rules affect TTFB, freshness and server cost.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering\u002F\"\n  }\n}\n",[919,927,928],{"type":921},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Framework Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Vue & Nuxt Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Nuxt Route Rules for Hybrid Rendering\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering\u002F\"\n    }\n  ]\n}\n",[930,931,932],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":201,"searchDepth":216,"depth":216,"links":934},[935,936,937,943,944,945,946,947,948,949,950,951],{"id":128,"depth":216,"text":129},{"id":160,"depth":216,"text":161},{"id":188,"depth":216,"text":189,"children":938},[939,940,941,942],{"id":193,"depth":234,"text":194},{"id":377,"depth":234,"text":378},{"id":384,"depth":234,"text":385},{"id":399,"depth":234,"text":400},{"id":551,"depth":216,"text":552},{"id":558,"depth":216,"text":559},{"id":569,"depth":216,"text":570},{"id":576,"depth":216,"text":577},{"id":717,"depth":216,"text":718},{"id":724,"depth":216,"text":725},{"id":754,"depth":216,"text":755},{"id":782,"depth":216,"text":783},{"id":893,"depth":216,"text":894},"How to assign the right rendering and caching mode to each route in Nuxt, and how route rules affect TTFB, freshness and server cost.","md",{"slug":12,"type":955,"breadcrumb":956,"datePublished":964,"dateModified":964},"article",[957,960,961,962],{"name":958,"url":959},"Home","\u002F",{"name":26,"url":25},{"name":21,"url":20},{"name":5,"url":963},"\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering\u002F","2026-10-06",true,"\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering",{"title":968,"description":969},"Nuxt Route Rules for Hybrid Rendering and Caching","Use Nuxt routeRules to prerender static pages, cache with SWR or ISR, render client-only dashboards and set headers, cutting TTFB and server load per route.","framework-performance\u002Fvue-and-nuxt-performance\u002Fnuxt-route-rules-for-hybrid-rendering\u002Findex","cCMl05t5VLU5ldnw2Biat1IVxiK6P2te2m_WVWFl8mk",[973,977],{"title":974,"path":975,"stem":976,"children":-1},"Lazy Hydration in Nuxt","\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Flazy-hydration-in-nuxt","framework-performance\u002Fvue-and-nuxt-performance\u002Flazy-hydration-in-nuxt\u002Findex",{"title":978,"path":979,"stem":980,"children":-1},"Reducing Nuxt Payload Size","\u002Fframework-performance\u002Fvue-and-nuxt-performance\u002Freducing-nuxt-payload-size","framework-performance\u002Fvue-and-nuxt-performance\u002Freducing-nuxt-payload-size\u002Findex",1791308073149]