Understanding Server-Side Rendering (SSR) with Nuxt: Features, Setup, and Best Practices
This article explains the concept of Server‑Side Rendering (SSR), why it improves SEO and first‑paint performance, compares popular SSR‑compatible frameworks, and provides a step‑by‑step guide for initializing a Nuxt project, configuring routing, SEO, styling, data fetching, state management, and extending functionality with modules.
What is SSR (Server‑Side Rendering)?
SSR means rendering the full HTML of a page on the server before sending it to the client, similar to traditional Java/ASP.NET/PHP approaches. Modern SSR is tightly coupled with front‑end frameworks like Vue or React and uses Node.js to render pages or components in a universal way.
Why use SSR?
SEO: Search engines such as Google , 百度 , Yandex , Bing and Yahoo can crawl a fully rendered page, improving indexability.
First‑paint speed: Unlike SPA, SSR returns a ready‑to‑display HTML, reducing the time before users see content.
Frameworks that support SSR
Open‑source library
Supported language
Stars
Description
Nuxt
Vue
54.9k
Fast scaffolding, type‑safe, high performance, extensible
Next
React
127k
Established framework, rich ecosystem, data‑fetch, styling
Quasar
Vue
26k
Rich UI, supports desktop and mobile
Remix
React
29.9k
Ultimate UX, zero‑config
What is Nuxt?
Nuxt is the leading full‑stack framework for Vue, offering out‑of‑the‑box SSR, file‑based routing, automatic imports, and a built‑in data‑fetch API. It mirrors Vue’s CSR development experience while handling SSR automatically.
File‑based routing: place pages in pages/ (e.g., pages/index.vue , pages/about.vue ).
Code splitting via Vue’s Virtual DOM, generating minimal chunks for faster load.
SSR is built‑in: develop as you would a CSR Vue app.
Automatic component import – no manual import Card from './Card.vue' needed.
Composable useFetch API for unified client/server data fetching.
Default Vite build, with optional Webpack or Rspack.
Nuxt’s architecture mirrors vue/core and splits functionality into packages such as nuxt (core engine), @nuxt/vite-builder , nuxt/webpack-builder , @nuxt/rspack-builder , nuxi (CLI), nitro (server engine), and @nuxt/kit (dev kit).
Getting Started
Initialize a project with the CLI:
npx nuxi@latest init nuxt-learn-examplesIf the download fails, add a host entry:
185.199.108.133 raw.githubusercontent.comThe latest Nuxt 3.14 project uses app.vue as the entry point and omits pages and plugins directories by default.
Routing
Nuxt uses Vue‑Router under the hood. Adding a file under pages/ automatically creates a route. Example directory:
- pages
- index.vue
- about.vue
- products
- [id].vueGenerated route configuration:
{
"routes": [
{ "path": "/index", "component": "pages/index.vue" },
{ "path": "/about", "component": "pages/about.vue" },
{ "path": "/products/:id", "component": "pages/products/[id].vue" }
]
}Use <NuxtLink to="/about">About</NuxtLink> for navigation; Nuxt prefetches linked pages automatically.
SEO and Meta
Set head information via useSeoMeta or component tags ( <Title> , <Meta> , <Link> , etc.). Example:
<script setup lang="ts">
useSeoMeta({
title: 'Taobei Shopping',
description: 'A shopping site even better than Taobao.',
ogImage: 'https://taobei.com/image.png'
})
</script>Alternatively, use useHead to add <Title> , <Meta> , <Style> , and external resources.
Styling
Place CSS in assets/ and import it in components or via nuxt.config.ts . Example:
import '~/assets/css/first.css'
<style>@import url("~/assets/css/second.css");</style>Global CSS can be added in nuxt.config.ts :
export default defineNuxtConfig({
css: ['~/assets/css/main.css']
})Data Fetching
Use useFetch , useAsyncData or the low‑level $fetch (alias of ofetch ) to retrieve data on both server and client. Example:
const { data, error, refresh } = await useFetch('/api/users')Options such as server: false or lazy: true control where and when the request runs. Caching is automatic based on the request URL or an explicit key .
State Management
Nuxt provides useState for SSR‑compatible shared state, and integrates with Pinia, Harlem, XState, etc. Example of a global counter:
const counter = useState('counter', () => Math.round(Math.random()*1000))Define reusable composables in composables/states.ts and import them anywhere.
Extending Nuxt with Modules
Nuxt’s module system lets you add plugins, components, routes, middleware, and more. There are already over 250 community modules. Create a new module with:
npx nuxi init -t module my-module
npm run dev:prepareDefine the module in src/module.ts using defineNuxtModule with meta , defaults , hooks , and a setup function that registers plugins, imports, and runtime code.
Conclusion
Nuxt brings Vue’s ecosystem to the server, offering out‑of‑the‑box SSR, file‑based routing, Pinia state management, and a rich module ecosystem, making it a low‑learning‑curve solution for developers familiar with Vue who need universal applications.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.