Nuxt 3 Route Rules: Designing Hybrid Rendering for Optimal Performance
Use Nuxt 3 route rules to assign SSR, SSG, ISR, or SWR to each page, balancing speed, freshness and security. This guide walks through requirements, design, trust boundaries, checks, and failure modes.
19 Aug 2026, 04:29 UTC

Problem & Takeaway
Modern web apps need a mix of static, dynamic and frequently updated pages. Nuxt 3’s routeRules let you pick a rendering strategy per route without writing multiple server‑side handlers. The key is to keep a single codebase, respect data‑access boundaries, and verify that each rule behaves as expected in the chosen deployment target.
Requirements
- Marketing and blog pages should be static for fast CDN delivery.
- Personal dashboards must render on each request with user‑specific data.
- News articles update hourly but can be served from cache between updates.
- Product catalog pages are semi‑dynamic: they need fresh data but can tolerate a 60‑second stale window.
- Deployment must run on a Nitro‑compatible platform (Vercel, Netlify, Cloudflare Pages, or a custom Node server with persistent storage).
Smallest Suitable Design
The minimal architecture uses routeRules in nuxt.config.ts to map patterns to rendering modes. Nitro generates the appropriate server entry points or static assets at build time, so you avoid a custom Express layer.
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
// Nitro handles caching headers automatically when rules are set
},
routeRules: {
// Static marketing home page
'/': { prerender: true },
// Static blog posts – generate all slugs at build time
'/blog/**': { prerender: true },
// Server‑side rendered admin area
'/admin/**': { ssr: true },
// Incremental Static Regeneration for hourly news updates
'/news/**': { isr: 3600 },
// Stale‑while‑revalidate for product catalog
'/products/**': { swr: 60 }
},
runtimeConfig: {
public: { apiBase: process.env.API_BASE },
private: { dbPassword: process.env.DB_PASSWORD }
}
});
Key points:
prerenderforces SSG at build time.ssrkeeps the route on the server on every request.isrre‑generates the page in the background after the specified period.swrserves stale content while a background refresh runs.- Runtime config is split into
public(sent to the client) andprivate(only on the server).
Trust & Data Boundaries
Nuxt distinguishes between server‑only and client‑visible code:
- SSR routes (e.g.,
/admin/**) can importdb-clientorfsbecause Nitro runs the handler in a Node environment. - SSG/ISR/SWR routes are built or executed at the edge. They must avoid importing server‑only modules. If a composable imports
db-client, it will crash the build for static routes. - Use
defineNuxtPluginwithmode: 'server'for logic that must stay server‑only, andmode: 'client'for client‑side only code. - When a route mixes SSR and SSG (e.g., a page that fetches user data on the client but renders a static header), guard the server import with a
process.servercheck.
Operational Checks
After building and deploying, perform the following checks to confirm each rule’s behavior:
- Local build verification
- Run
nuxi build. - Inspect
.output/publicfor static HTML files. A file namedindex.htmlindicatesprerender: true. - Check
.output/serverfor_ssr.jsentries – these are SSR handlers.
- Run
- Deployment header inspection
- Use
curl -I https://example.com/blog/post-1to confirmCache-Control: public, max-age=0, s-maxage=31536000for static pages. - For ISR pages, look for
x-nitro-cache: staleorCache-Control: stale-while-revalidate=60headers. - For SWR pages,
Cache-Control: stale-while-revalidate=60should be present.
- Use
- Runtime config audit
- In a browser console, run
console.log(useRuntimeConfig().public)–privatekeys must not appear. - Run
npx @nuxt/test-utils runto mount the app and assert thatuseRuntimeConfig().privateis undefined on the client.
- In a browser console, run
- Edge function validation
- Deploy to Vercel and use
vercel logsto ensure that edge‑only routes (e.g.,/products/**) hit the edge runtime and not a Node server. - Check the build output for
edge-functionsdirectory.
- Deploy to Vercel and use
Failure Modes & Mitigation
- ISR stampede: If many requests hit a page while it’s being regenerated, they can all trigger a rebuild. Mitigate by configuring
swr: 60on high‑traffic pages or by using Nitro’srevalidate: 'background'feature. - Dynamic data at build time: A SSG route that calls
$fetchto an API without a fallback will fail if the API is down. Usetry/catchand provide afallbackcomponent. - Edge deployment breakage: Importing
fsornetin a composable used by a SWR route will cause a build error. Audit composables withnpx nuxi analyze. - Middleware bypass on static pages: Auth middleware runs only on SSR or edge routes. For static pages that need client‑side auth, add a
useRouteGuardcomposable that checksuseAuth()on the client.
When the Design Changes
- Platform limits (e.g., Vercel’s 1000 static pages) force you to switch from
prerendertoisrorswr. - If personalization grows, more routes may need
ssr: truewith a caching layer (e.g., Cloudflare Workers KV) to avoid per‑request database hits. - Adopting micro‑frontends could push route handling to a gateway; in that case
routeRulesbecome per‑service rather than per‑page. - Adding real‑time features (WebSockets) would require moving those routes out of Nitro’s static/edge context into a dedicated Node server.
Practical Checklist
| Check | How to Verify | Expected Result |
|---|---|---|
| Static page generated | Inspect .output/public/index.html | Exists and contains full HTML |
| SSR handler present | Look for _ssr.js in .output/server | File exists for /admin/** |
| ISR cache header | curl -I on /news/** | Cache-Control: stale-while-revalidate=60 |
| SWR header | curl -I on /products/** | Cache-Control: stale-while-revalidate=60 |
| Runtime config privacy | Console log useRuntimeConfig() on client | No private keys exposed |
Conclusion
Nuxt 3’s routeRules provide a declarative, zero‑code‑change way to assign the right rendering strategy to each page. By respecting trust boundaries, verifying build output, and monitoring runtime headers, you can deliver fast, fresh, and secure content across a single codebase. Keep in mind the limits of your deployment platform and the potential for cache stampedes, and adjust your rules accordingly.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.