404 Not Found

404 Not Found


nginx

SSR and CSR Rendering Modes

Charlie discovered that all pages on MegaShop use SSR, putting enormous strain on the servers—with millions of product pages being rendered with every request. The content on the homepage rarely changes, yet it is re-rendered with every request. The admin panel doesn't require SEO, yet it is rendered on the server. Hybrid rendering allows each page to choose the optimal strategy: SSG for the homepage, ISR for product lists, SSR for detail pages, and CSR for the user center.

1. What You'll Learn


2. A True Story of an Architect

(1) Pain Point: Site-wide SSR Overwhelms the Server

MegaShop handles 5,000 requests per second, all via SSR. The content on the homepage changes only once a day, yet it is rendered with every request. The product list is updated hourly, resulting in the repeated rendering of a million product detail pages. The server's CPU usage has reached 90%, so Bob is planning to add 10 more servers.

(2) Solutions for Hybrid Rendering

Nuxt 3's routeRules allow each route to have its own rendering strategy:

TYPESCRIPT
// nuxt.config.ts
routeRules: {
  '/': { prerender: true },        // Homepage: build once
  '/products': { swr: 3600 },      // Product list: cache 1 hour
  '/products/**': { swr: 86400 },  // Product detail: cache 1 day
  '/admin/**': { ssr: false }      // Admin: client only
}

(3) Benefits: 85% reduction in server load

After implementing hybrid rendering, SSR requests dropped from 5,000 per second to 750 per second, the number of servers was reduced from 10 to 3, and costs were cut by 70%.


3. routeRules Rendering Mode

(1) Hybrid Rendering Decision Tree

100%
flowchart TB
    A[Page Request] --> B{Needs SEO?}
    B -->|No| C[CSR - ssr: false]
    B -->|Yes| D{Content changes?}
    D -->|Never| E[SSG - prerender: true]
    D -->|Rarely| F[ISR - swr: seconds]
    D -->|Frequently| G[SSR - default mode]
    D -->|Varies by region| H[ESR - edge rendering]
    C --> I[Admin / Dashboard / User Center]
    E --> J[About / Legal / Landing]
    F --> K[Product List / Category Pages]
    G --> L[Product Detail / Search Results]
    H --> M[Global Homepage / Regional Content]

(2) Quick Reference for the routeRules Option

Option Value Effect Applicable Scenarios
ssr boolean SSR switch false = CSR
csr boolean CSR switch Legacy option
swr number/string ISR cache duration (seconds) Pages updated periodically
prerender boolean Pre-render during build Static page
hydrate boolean Hydrate only, do not render Special optimization
redirect string 301/302 redirect URL migration
cors boolean cross-origin API routing
headers object custom response headers caching/security

(1) ▶ Example: Complete routeRules configuration

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Homepage: pre-render at build time
    '/': { prerender: true },

    // Static pages
    '/about': { prerender: true },
    '/privacy': { prerender: true },

    // Product list: ISR with 1 hour cache
    '/products': { swr: 3600 },

    // Product detail: ISR with 24 hour cache
    '/products/**': { swr: 86400 },

    // Categories: ISR with 6 hour cache
    '/categories/**': { swr: 21600 },

    // Admin: client-side rendering only
    '/admin/**': { ssr: false },

    // User pages: client-side
    '/profile/**': { ssr: false },

    // API: CORS headers
    '/api/**': { cors: true },

    // Redirects
    '/shop/': { redirect: '/products/', redirectCode: 301 },

    // Custom headers for static assets
    '/_nuxt/**': { headers: { 'cache-control': 'max-age=31536000' } }
  }
})

Output:

TEXT
// Execution Successful

4. ISR Incremental Static Regeneration

(1) ISR Workflow

100%
sequenceDiagram
    participant U as User
    participant C as CDN/Cache
    participant S as Nuxt Server
    participant D as Database

    U->>C: GET /products/123
    C->>C: Cache HIT? (within swr period)
    C-->>U: Cached HTML (instant)
    
    Note over C,S: After swr period expires
    U->>C: GET /products/123
    C->>C: Cache STALE
    C-->>U: Stale HTML (still fast)
    C->>S: Background revalidation
    S->>D: Fetch latest data
    D-->>S: Updated data
    S-->>C: Fresh HTML
    Note over C: Next request gets fresh HTML

(2) Comparison of ISR, SSR, and SSG

Dimension SSR SSG (prerender) ISR (swr)
Rendering Timing On Every Request During Build Background Refresh After Cache Expires
Response Time 🟡 Medium 🟢 Fastest 🟢 Fast (Cache Hit)
Data Freshness ✅ Latest ❌ Fixed at build time ⚠️ Maximum delay = swr seconds
Server Load 🔴 High 🟢 Lowest 🟢 Low
Use Cases Real-time Data Never Changes Scheduled Updates

(1) ▶ Example: ISR Product List Page

TYPESCRIPT
// nuxt.config.ts - ISR configuration
export default defineNuxtConfig({
  routeRules: {
    // Product list: serve from cache, revalidate every 60 seconds
    '/products': { swr: 60 },
    // Product detail: cache for 1 hour
    '/products/**': { swr: 3600 }
  }
})

Output:

TEXT
// Execution Successful

(2) ▶ Example: Programmatic ISR Cache Invalidation

TYPESCRIPT
// server/api/invalidate-cache.post.ts
export default defineEventHandler(async (event) => {
  const { path } = await readBody(event)

  // Purge specific cached route
  await useStorage('cache').removeItem(`nitro:routes:${path}`)

  return { message: `Cache invalidated for ${path}`, timestamp: Date.now() }
})

Output:

TEXT
// Execution Successful

5. ESR Edge Rendering

(1) Principles of Edge Rendering

ESR (Edge Side Rendering) performs rendering at CDN edge nodes, and users retrieve the HTML from the nearest node.

Dimension Central SSR ESR
Server Location Single Region Global Edge Nodes
Latency Depends on distance Minimum (local access)
Use Cases Single-Region Users Global Users
Nitro Presets node-server cloudflare-pages / vercel-edge

(1) ▶ Example: Vercel Edge Deployment Configuration

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'vercel-edge'
  },
  routeRules: {
    // Homepage rendered at edge for global users
    '/': { swr: 3600 },
    '/products/**': { swr: 86400 }
  }
})

Output:

TEXT
// Execution Successful

6. MegaShop Hybrid Rendering Strategy

(1) Planning the MegaShop Page Rendering Strategy

Page URL Strategy SWR Reason
Home / SSG - Stable content, rendered during build
About Page /about SSG - Virtually Unchanged
Product List /products ISR 3600 Products updated hourly
Category Page /categories/** ISR 21600 Updated Daily
Product Details /products/** ISR 86400 Updated Daily
Search Results /search SSR - Real-time Query
Shopping Cart /cart CSR - For Members Only
User Center /profile/** CSR - No SEO required
Admin Panel /admin/** CSR - No SEO required
API /api/** - - Data-only API

(1) ▶ Example: Complete routeRules for MegaShop

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true,

  routeRules: {
    // SSG: Pre-render at build time
    '/': { prerender: true },
    '/about': { prerender: true },
    '/privacy': { prerender: true },
    '/contact': { prerender: true },

    // ISR: Cache with revalidation
    '/products': { swr: 3600 },           // 1 hour
    '/categories/**': { swr: 21600 },     // 6 hours
    '/products/**': { swr: 86400 },       // 24 hours

    // SSR: Real-time rendering
    '/search': { swr: 0 },

    // CSR: Client-side only
    '/cart': { ssr: false },
    '/checkout/**': { ssr: false },
    '/profile/**': { ssr: false },
    '/admin/**': { ssr: false },

    // API
    '/api/**': { cors: true },

    // Static assets: long cache
    '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } },
    '/images/**': { headers: { 'cache-control': 'public, max-age=86400' } }
  }
})

Output:

TEXT
// Execution Successful

(2) Solution for ISR Cache Expiration on Product Pages with Millions of Items

Event Expiration Policy Implementation
Product Price Update Inactive Product Page useStorage('cache').removeItem()
New Products List of Expired Products Batch Expire /products Cache
Category Changes Inactive Category Pages Inactive /categories/xxx
Sitewide Sale Clear All Product Pages Clear Entire Cache
Inventory Changes Expired Products Webhook Trigger

7. Comprehensive Example: Verifying MegaShop Rendering Modes

VUE
<!-- pages/admin/dashboard.vue - CSR mode -->
<template>
  <div>
    <h1>Admin Dashboard</h1>
    <p>Rendering mode: Client-Side Only</p>
    <p>Current time: {{ currentTime }}</p>
  </div>
</template>

<script setup lang="ts">
// CSR: this page is NOT server-rendered
definePageMeta({ ssr: false, layout: 'sidebar' })

const currentTime = ref(new Date().toISOString())
onMounted(() => {
  setInterval(() => {
    currentTime.value = new Date().toISOString()
  }, 1000)
})
</script>
VUE
<!-- pages/products/[id].vue - ISR mode -->
<template>
  <div v-if="product">
    <h1>{{ product.name }}</h1>
    <p>${{ product.price }} USD</p>
    <p>Cache: revalidated every 24 hours</p>
  </div>
</template>

<script setup lang="ts">
// ISR: cached for 24 hours via routeRules swr: 86400
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
</script>

❓ FAQ

Q What is the unit of measurement for swr?
A Seconds. swr: 60 indicates a 60-second cache; after it expires, the next request triggers a background refresh, but the current request still returns the old cached data.
Q Can prerender and SWR be used together?
A Yes. { prerender: true, swr: 3600 } indicates prerendering during the build process, followed by a refresh using the ISR caching strategy.
Q Where is the ISR cache stored?
A It depends on the Nitro preset. The Node.js preset stores it in memory or on the file system; the Vercel preset uses Vercel KV; and Cloudflare uses KV storage.
Q What does the CSR page return during SSR?
A It returns an empty HTML template (containing only <div id="__nuxt"></div> and the JS bundle); all content is rendered on the client side.
Q How can I verify which rendering mode the current page is using?
A View the source code (Ctrl+U)—if there is content, it's SSR/SSG/ISR; if it's empty, it's CSR. The response header x-nuxt-render-mode also indicates the rendering mode.
Q Will the ISR cache for millions of product pages fill up the storage?
A Popular products naturally remain in the cache, while less popular ones are automatically evicted once they expire. There's no need to pre-cache all million pages; only those that have been accessed are cached.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty: ⭐): Configure routeRules to enable pre-rendering of the home page and CSR for the admin page, then verify the differences in the "View Source" output between the two modes.
  2. Advanced Exercise (Difficulty ⭐⭐): Configure ISR (swr: 60) for the product list, and after 60 seconds, refresh the page to see if the data has been updated.
  3. Challenge (Difficulty: ⭐⭐⭐): Implement the ISR cache invalidation API. When product data is updated, call /api/invalidate-cache to invalidate the corresponding cache, and verify that the next request retrieves the new data.

---|

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏