SkillByAIOpen interactive version →

Lesson 24 / 25

Nuxt and Server-Side Rendering

When to render on the server.

SSR, hydration and Nuxt

A plain Vue app renders in the browser, so the first HTML is nearly empty until JavaScript runs. Server-side rendering (SSR) renders the HTML on the server for faster first paint and better crawlability, then hydrates it in the browser to make it interactive. The server and client output must match, so browser-only APIs (window, localStorage) belong in onMounted, which does not run on the server. Nuxt is the full-stack framework built on Vue that provides SSR, static generation, file-based routing in pages/, auto-imports, server API routes in server/ and data helpers such as useFetch and useAsyncData. Choose it for content sites, SEO-sensitive pages and full-stack apps; a Vite SPA is simpler for apps behind a login. Nuxt conventions differ between major versions, so check the docs for your version.

A Nuxt page with server data

File-based routing and useFetch.

<!-- pages/products/[id].vue  ->  route /products/:id -->
<script setup>
const route = useRoute()               // auto-imported in Nuxt

// runs on the server during SSR; the result is transferred to the client
const { data: product, error } = await useFetch(`/api/products/${route.params.id}`)

useHead({ title: () => product.value?.name ?? 'Product' })
</script>

<template>
  <p v-if="error">Product not found</p>
  <article v-else-if="product">
    <h1>{{ product.name }}</h1>
    <p>{{ product.description }}</p>
  </article>
</template>

<!-- server/api/products/[id].get.js would implement the API route -->

A printed menu versus a chalkboard

SSR hands guests a printed menu as they sit down (ready HTML); a client-rendered app gives them a blank chalkboard that a waiter fills in after arriving (JavaScript).

Quick check: Why should code that uses window or localStorage go in onMounted in an SSR app?

  • window is faster inside lifecycle hooks
  • onMounted runs before the server responds
  • onMounted runs only in the browser, not during server rendering
  • SSR disables all other hooks
Answer

onMounted runs only in the browser, not during server rendering — The server has no browser globals.