Vue 3 and Nuxt · Building Apps with Nuxt

Rendering Modes and Route Rules

Choose rendering per route with routeRules: prerendering, stale-while-revalidate caching, client-only pages, redirects and headers.

Create a free account to save this page, take notes and track your progress. Sign in

What you'll build

One Nuxt app with different rendering per route: a prerendered home page, blog posts cached with stale-while-revalidate, a client-only account area, a redirect from old URLs, and no-store headers on the API. Server logs show which requests actually render.

The idea

  • Universal rendering (SSR + hydration) is the default: every request renders on the server.
  • routeRules in nuxt.config.ts change this per route pattern:
    • prerender: true renders at build time into static HTML;
    • swr: seconds caches the rendered response and refreshes it in the background;
    • isr is the CDN-level equivalent on supported hosts;
    • ssr: false sends an app shell and renders in the browser (fine for private dashboards, bad for SEO);
    • redirect and headers apply without rendering.

The code

Prerender, SWR cache, client-only, redirects and headers
// file: nuxt.config.ts
export default defineNuxtConfig({
  compatibilityDate: "2026-10-01",
  devtools: { enabled: false },
  routeRules: {
    "/": { prerender: true },
    "/blog/**": { swr: 3600 },
    "/account/**": { ssr: false },
    "/old-blog/**": { redirect: { to: "/blog/**", statusCode: 301 } },
    "/api/**": { headers: { "cache-control": "no-store" } },
  },
});

// file: app/app.vue
<template><main><NuxtPage /></main></template>

// file: app/pages/index.vue
<script setup lang="ts">
console.log("[app] rendering home");
</script>
<template><h1>Welcome</h1></template>

// file: app/pages/blog/[slug].vue
<script setup lang="ts">
const slug = useRoute().params.slug;
console.log(`[app] rendering blog post ${slug}`);
</script>
<template><h1>Post: {{ slug }}</h1></template>

// file: app/pages/account/index.vue
<template><h1>Your account</h1></template>

// file: server/api/time.get.ts
export default defineEventHandler(() => ({ now: "fresh on every request" }));

// headers: cache-control, x-nitro-prerender
// request: GET /
// request: GET /blog/hello
// request: GET /blog/hello
// request: GET /account find:"Your account"
// request: GET /old-blog/hello
// request: GET /api/time

Output

GET / -> 200
Welcome
GET /blog/hello -> 200 (cache-control: s-maxage=3600, stale-while-revalidate)
[app] rendering blog post hello
Post: hello
GET /blog/hello -> 200 (cache-control: s-maxage=3600, stale-while-revalidate)
Post: hello
GET /account -> 200
response contains "Your account": no
GET /old-blog/hello -> 301 (Location: /blog/hello)
GET /api/time -> 200 (cache-control: no-store)
{"now": "fresh on every request"}

Run this on your computer — see “Get Started” for setup.

The home page rendered at build time, so no request logs "rendering home". The blog post rendered once; the second request came from the SWR cache. The account page HTML doesn't contain its heading: it renders in the browser. The redirect and the API header applied without rendering anything.

Common mistakes

  • Prerendering pages with per-user content; everyone gets the same HTML.
  • ssr: false on public pages that need search traffic.
  • SWR-caching responses that depend on cookies (per-user data cached for everyone).
  • Running several server instances with the default in-memory cache and expecting shared caching; configure Nitro storage (Redis) for the cache.

Key points

  • SSR by default; routeRules choose per route.
  • prerender for static pages, swr/isr for cacheable dynamic pages, ssr: false for private app areas.
  • Redirects and headers can be route rules too.

Further reading: Rendering modes · Hybrid rendering · Nitro cache storage

Practice questions

What does swr in Nuxt route rules do?

Answer

It caches the rendered response on the server for the given time and serves it, regenerating it in the background when it becomes stale.

When is ssr: false appropriate?

Answer

For private, highly interactive areas like dashboards that don't need SEO; the server sends an app shell and the browser renders the page.

Why shouldn't you prerender or SWR-cache per-user pages?

Answer

The cached HTML is shared by all visitors, so one user's content would be shown to others.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?