Vue · SSR

Vue 3 SSR with Nuxt — A Field Guide

You can hand-roll Vue 3 SSR, but for anything real, Nuxt is the pragmatic answer. The interesting decisions are which rendering mode to use and how to write code that runs on both sides.

John Kihiu12 min read

Server-side rendering makes a Vue app return real HTML on the first request — for SEO, faster first paint, and working link previews — instead of an empty shell the client fills in. Vue 3 supports SSR directly, but wiring it up by hand (server bundle, hydration, routing, data fetching) is a lot of undifferentiated work. For any real project, Nuxt is the pragmatic path, and the decisions worth your attention are its rendering modes and the universal-code gotchas.

Why Nuxt over hand-rolling

Hand-building Vue SSR means solving the same problems Nuxt already solved: a server render pipeline, client hydration, file-based routing, data fetching that works on both server and client, and build configuration for two targets. Nuxt packages all of it into a framework, so you write your app and get SSR, routing, and data fetching for free. Unless you have an unusual constraint, reinventing that stack is effort spent on plumbing rather than product.

Rendering modes

ModeRendersBest for
SSR (universal)On the server per request, hydrates on clientDynamic, SEO-sensitive content
SSG (static)At build time to static HTMLContent that rarely changes — marketing, docs, blogs
SPA (client-only)In the browser, no server renderApp-like, auth-gated dashboards where SEO is irrelevant

Nuxt lets you choose per route, and often the right answer is a mix: statically generate the marketing and blog pages, server-render the dynamic public pages, and leave the authenticated app as a client-side SPA. Matching the mode to each route's needs is where the real optimisation is.

Universal-code gotchas

The defining challenge of SSR is that your code runs in two environments — Node on the server, then the browser. Code that assumes browser globals breaks on the server:

Hydration mismatches are the classic SSR bug

If the server renders one thing and the client expects another — because of a browser-only value, a timestamp, or randomness in the initial render — Vue throws a hydration mismatch and the benefit is lost. Keep the initial render deterministic and identical on both sides, and defer anything browser-specific until after hydration. Most SSR debugging is chasing these mismatches.

Vue 3 SSR is best reached through Nuxt, which packages the server pipeline, hydration, routing, and data fetching so you build product instead of plumbing. Choose the rendering mode per route — static for content, SSR for dynamic public pages, SPA for the app — and write universal code carefully, guarding browser globals and keeping the initial render identical on both sides to avoid hydration mismatches. That is where SSR is won or lost.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.