Conrad Nuxt docs

Rendering and lifecycle

CSR, SSR and prerendering, route rules (swr, isr, prerender, ssr false, cors, proxy), data baked into prerendered pages, CORS, the order things run on the server and in the browser, and server components with nuxt-client and slots.

From the rendering modes, CORS, lifecycle and server components parts of your Concepts note, and the prerendering part of Getting started III.

Know

  • Three modes: CSR sends a shell and builds the page in the browser; SSR renders HTML per request and hydrates; SSG (prerendering) renders once at build time, data included, and serves files. Nuxt defaults to SSR plus hydration.
  • Route rules per path: prerender: true, swr: <seconds> (Nitro caches the response and refreshes it in the background), isr (the same, but cached in the platform's CDN, on Vercel and Netlify only), ssr: false, redirect, proxy, cors, headers.
  • Prerendered data is frozen: useFetch runs during the build and the result is in the HTML and _payload.json. Live parts need server: false (plus lazy: true). With a fully static nuxt generate there are no server routes in production: /api works only during the build, so live parts must call an absolute URL on a server that exists (and that allows your origin with CORS); with a prerender route rule on a deployed Nuxt server, relative /api URLs keep working.
  • CORS: a browser rule about reading cross-origin responses; servers and curl ignore it. cors: true sends Access-Control-Allow-Origin: * with any method and header, fine for public data. Someone else's API without CORS is reached through your own server: a proxy rule or a server route.
  • Order on the server: Nitro plugins (once, at start-up) → server middleware → app plugins → validate → route middleware → page setup and data fetching → HTML with payload (render:html). In the browser: app plugins → validate → route middleware → mount and hydrate → onMounted and the rest.
  • Server components: .server.vue, rendered on the server only, no JavaScript shipped. Isolated: no shared state, own useRoute(), no route middleware, props as query parameters, a round trip per island on client navigation. Parent slots are interactive; nuxt-client children are hydrated with selectiveClient.

Fact check of your notes

Gotcha· CORS doesn't cancel the request on the server

"By default checks the same origin. If it differs, will cancel the request": the check is done by the browser, not the server. A simple cross-origin request is sent and reaches the server; the browser just won't let the script read the answer. Other requests get a preflight OPTIONS first and are only sent if it's allowed. Anything outside a browser ignores CORS, so it is never a replacement for authentication.

Gotcha· isr only means something on platforms with a CDN that supports it

"isr: 3600 — like SWR, but cached on CDNs": only the Vercel and Netlify presets act on isr. On a Node server or Cloudflare, Nitro ignores it and nothing is cached at all, so use swr there.

Gotcha· nuxt-client needs to be switched on

"Add the nuxt-client attribute, which will make it a regular component": it works only with experimental.componentIslands.selectiveClient enabled, and the child is still rendered on the server as part of the island, then hydrated on its own. Server components as a whole are still marked experimental (enabled automatically when a .server.vue exists).

Exercise

Exercise
  • In a playground, add route rules for / (prerender), /products/** (swr: 60) and /admin/** (ssr: false), run nuxt build && node .output/server/index.mjs, and compare the HTML and response headers of the three in the network panel.
  • Prerender a page that shows new Date().toISOString() from an API route, rebuild a minute later, and watch the value change only with the build; then load it with server: false.
  • Turn a component into .server.vue, check that its chunk is gone from the client, then add a nuxt-client child with selectiveClient on.

Be able to say

Be able to say· What runs, in order, when a Nuxt page is requested?

"Nitro plugins have run once at start-up. Per request, server middleware runs first, then Nuxt creates a new app and runs the app plugins, then the page's validate and the route middleware, then the page's setup with useFetch awaited, and the result is rendered to HTML with a payload. In the browser the plugins, validation and middleware run again, Vue hydrates the HTML using the payload, and only then do onMounted hooks run; they never run on the server."

Be able to say· When would you use a Nuxt server component?

"For heavy parts that are never interactive, like rendered Markdown or a CMS block: the HTML is in the page but neither the component's code nor its dependencies go to the browser. The price is isolation, so no shared state with the page, props passed as query parameters, and a server round trip per island on client-side navigation. Interactive bits go in through slots or a nuxt-client child."

Your notes

Open in Notes

Nothing yet. Notes filed here show up on this page and the section overview.