# Nuxt 3: SSR en statische generatie, de complete gids > Beheers SSR en statische generatie met Nuxt 3. Van useFetch tot route rules: leer hoe Vue.js-applicaties optimaal presteren. - Published: 2026-02-11 - Updated: 2026-04-28 - Author: SharpSkill - Tags: nuxt 3, vue.js, ssr, statische generatie, web performance - Reading time: 12 min --- Nuxt 3 verandert de manier waarop Vue.js-applicaties gebouwd worden door meerdere renderingmodi aan te bieden die geschikt zijn voor uiteenlopende use cases. Van Server-Side Rendering (SSR) tot statische generatie en hybride rendering biedt het framework opmerkelijke flexibiliteit om performance en SEO te optimaliseren. > **Vereisten** > > Deze tutorial gaat uit van basiskennis van Vue 3 en de Composition API. Bekendheid met server-side rendering is handig maar niet verplicht, omdat de fundamenten in de gids worden uitgelegd. ## De renderingmodi van Nuxt 3 begrijpen Voordat men in de code duikt, is het essentieel om de verschillen tussen de beschikbare renderingmodi te begrijpen. Elke modus speelt in op specifieke behoeften qua performance, SEO en gebruikerservaring. SSR (Server-Side Rendering) genereert de HTML op de server bij elke request. Statische generatie (SSG) pre-genereert alle pagina's tijdens de build. De hybride modus maakt het mogelijk deze benaderingen per pagina te combineren. ```typescript // nuxt.config.ts // Configuratie van de verschillende renderingmodi export default defineNuxtConfig({ // SSR standaard ingeschakeld (aanbevolen voor SEO) ssr: true, // Statische generatie: pre-rendert alle pagina's // Gebruik 'npm run generate' om te bouwen // target: 'static', // Nuxt 2 syntax // Hybride modus: per route configureerbaar routeRules: { // Homepagina: pre-gerenderd en gecached '/': { prerender: true }, // Blog: statische generatie '/blog/**': { prerender: true }, // Dashboard: alleen client-side rendering '/dashboard/**': { ssr: false }, // API: geen pre-rendering '/api/**': { prerender: false } } }) ``` Deze configuratie toont de kracht van de hybride modus: elke sectie van de applicatie gebruikt de renderingmodus die het beste past bij haar behoeften. ## Data ophalen met useFetch en useAsyncData Nuxt 3 biedt twee belangrijke composables om data isomorf op te halen. Deze composables werken zowel server- als client-side, met automatisch hydratatiebeheer. `useFetch` is een wrapper rond `useAsyncData` die HTTP-aanroepen vereenvoudigt. `useAsyncData` biedt meer controle voor geavanceerde scenario's. ```vue ``` Voor situaties die meer controle vragen, kan `useAsyncData` elke asynchrone functie uitvoeren. ```vue ``` Deze composables voorkomen dubbele fetches: data die op de server is opgehaald wordt geserialiseerd in de HTML-payload en hergebruikt tijdens de client-hydratatie. ## SSR aanpassen met server hooks De SSR van Nuxt 3 kan via server hooks aangepast worden. Deze hooks maken het mogelijk in te grijpen op verschillende momenten van de renderingcyclus om standaardgedrag aan te passen. ```typescript // server/plugins/render-hooks.ts // Server-plugin om SSR-rendering aan te passen export default defineNitroPlugin((nitroApp) => { // Hook die voor het renderen van elke pagina draait nitroApp.hooks.hook('render:html', (html, { event }) => { // Scripts of metadata injecteren html.head.push(` `) }) // Hook voor beheer van de render-cache nitroApp.hooks.hook('render:response', (response, { event }) => { // Aangepaste cache-headers toevoegen const path = event.path if (path.startsWith('/blog/')) { // Lange cache voor blogartikelen response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400' } else if (path.startsWith('/api/')) { // Geen cache voor API's response.headers['Cache-Control'] = 'no-store' } }) }) ``` > **SSR-performance** > > De hook `render:response` is ideaal om HTTP-cachingstrategieën te implementeren. SSR combineren met een CDN dat Cache-Control-headers respecteert, maakt het mogelijk pre-gerenderde pagina's te serveren met behoud van invalidatiemogelijkheden. ## Statische generatie met nuxt generate Statische generatie bouwt alle pagina's vooraf tijdens de build. Deze aanpak is ideaal voor sites met stabiele content zoals blogs, documentatie of marketingsites. Voor dynamische routes moet Nuxt alle te genereren URL's kennen. De hook `prerender:routes` maakt het mogelijk deze routes programmatisch te definiëren. ```typescript // nuxt.config.ts // Volledige configuratie voor statische generatie export default defineNuxtConfig({ // Statische generatie inschakelen nitro: { prerender: { // Automatisch crawlen van links inschakelen crawlLinks: true, // Routes die altijd opgenomen moeten worden routes: ['/', '/about', '/contact'], // Bepaalde routes negeren ignore: ['/admin', '/api'] } }, hooks: { // Hook om dynamische routes te genereren async 'prerender:routes'(ctx) { // Artikelen ophalen uit API of DB const articles = await fetch('https://api.example.com/articles') .then(res => res.json()) // Artikelroutes toevoegen for (const article of articles) { ctx.routes.add(`/blog/${article.slug}`) } // Categorieën ophalen const categories = await fetch('https://api.example.com/categories') .then(res => res.json()) for (const category of categories) { ctx.routes.add(`/category/${category.slug}`) } } } }) ``` Voor projecten met veel pagina's kan de automatische crawler tekortschieten. Hier volgt een robuustere aanpak met een apart configuratiebestand. ```typescript // server/utils/generate-routes.ts // Hulpfunctie om de lijst met dynamische routes te genereren import { prisma } from './prisma' export async function getAllStaticRoutes(): Promise { const routes: string[] = [] // Blogartikelen const articles = await prisma.article.findMany({ where: { published: true }, select: { slug: true, category: { select: { slug: true } } } }) for (const article of articles) { routes.push(`/blog/${article.category.slug}/${article.slug}`) } // Productpagina's const products = await prisma.product.findMany({ where: { active: true }, select: { slug: true } }) for (const product of products) { routes.push(`/products/${product.slug}`) } // Tagpagina's const tags = await prisma.tag.findMany({ select: { slug: true } }) for (const tag of tags) { routes.push(`/tags/${tag.slug}`) } return routes } ``` ## Hybride rendering met routeRules Hybride rendering is de paradepaardje-feature van Nuxt 3. Het stelt in staat verschillende renderingregels per route te definiëren en zo het beste van SSR en SSG te combineren. ```typescript // nuxt.config.ts // Geavanceerde configuratie voor hybride rendering export default defineNuxtConfig({ routeRules: { // Marketingpagina's: pre-gerenderd en lange tijd gecached '/': { prerender: true }, '/pricing': { prerender: true }, '/features/**': { prerender: true }, // Blog: ISR (Incremental Static Regeneration) // Revalidatie elk uur '/blog/**': { isr: 3600, prerender: true }, // Documentatie: CDN-cache met revalidatie '/docs/**': { swr: 86400, // Stale-while-revalidate prerender: true }, // E-commerce: SSR met korte cache '/products/**': { ssr: true, cache: { maxAge: 60, staleMaxAge: 300 } }, // Winkelwagen en checkout: alleen client-side '/cart': { ssr: false }, '/checkout/**': { ssr: false }, // Dashboard: SPA-modus '/dashboard/**': { ssr: false, // Pre-rendering uitschakelen prerender: false }, // API-routes: standaard geen cache '/api/**': { cors: true, headers: { 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE' } } } }) ``` Deze configuratie illustreert een typische architectuur voor moderne applicaties: openbare pagina's worden voor SEO geoptimaliseerd met SSG, terwijl interactieve secties client-side rendering gebruiken. ## Performanceoptimalisatie met datacaching Naast paginacaching maakt Nuxt 3 het mogelijk opgehaalde data te cachen. Deze strategie verlaagt de belasting op API's en verbetert responstijden. ```typescript // server/api/articles/[slug].get.ts // API-endpoint met datacaching import { getArticleBySlug } from '~/server/utils/articles' export default defineCachedEventHandler( async (event) => { const slug = getRouterParam(event, 'slug') if (!slug) { throw createError({ statusCode: 400, message: 'Slug ontbreekt' }) } const article = await getArticleBySlug(slug) if (!article) { throw createError({ statusCode: 404, message: 'Artikel niet gevonden' }) } return article }, { // Cachekey op basis van de slug getKey: (event) => `article-${getRouterParam(event, 'slug')}`, // Cacheduur: 1 uur maxAge: 3600, // Stale-while-revalidate: oude cache serveren tijdens update staleMaxAge: 7200, // Tag-gebaseerde invalidatie tags: ['articles'] } ) ``` Om de cache te invalideren bij contentwijzigingen biedt Nuxt een tagsysteem. ```typescript // server/api/articles/[slug].put.ts // Artikel bijwerken met cache-invalidatie import { updateArticle } from '~/server/utils/articles' export default defineEventHandler(async (event) => { const slug = getRouterParam(event, 'slug') const body = await readBody(event) // Het artikel bijwerken const article = await updateArticle(slug, body) // Cache voor dit artikel invalideren await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`) // Of tag-gebaseerde invalidatie (alle artikelen) // await useStorage('cache').clear('articles') return article }) ``` > **Gedistribueerde cache** > > In productie met meerdere instanties is in-memory cache onvoldoende. Het wordt aangeraden Redis of een ander gedistribueerd systeem te configureren via de Nitro-configuratie om consistentie tussen instanties te garanderen. ## SEO en metadata beheren SSR maakt SEO-optimalisatie mogelijk door metadata server-side te genereren. Nuxt 3 biedt verschillende benaderingen om meta tags dynamisch te beheren. ```vue ``` Voor statische pagina's kan de metadata direct in het component gedefinieerd worden. ```vue ``` ## Deployment en productieoverwegingen De deploymentkeuze hangt af van de gebruikte renderingmodus. Hier de belangrijkste opties en hun configuraties. ```typescript // nuxt.config.ts // Configuratie voor verschillende deployomgevingen export default defineNuxtConfig({ nitro: { // Preset afhankelijk van het doelplatform // preset: 'vercel', // Vercel // preset: 'netlify', // Netlify // preset: 'cloudflare-pages', // Cloudflare // preset: 'node-server', // Klassieke Node.js // Configuratie voor Node.js in productie preset: 'node-server', // Compressie van responses compressPublicAssets: true, // Configuratie van de cache-storage storage: { cache: { driver: 'redis', url: process.env.REDIS_URL } } }, // Runtime omgevingsvariabelen runtimeConfig: { // Geheimen (niet blootgesteld aan de client) apiSecret: process.env.API_SECRET, // Publieke configuratie public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api' } } }) ``` Voor statische deployment maakt het commando `npm run generate` een map `.output/public` aan die klaar is om bij elke statische bestandshost geplaatst te worden. ```bash # Statische generatie npm run generate # De inhoud van .output/public kan ingezet worden op: # - Vercel (automatische detectie) # - Netlify (automatische configuratie) # - GitHub Pages # - S3 + CloudFront # - Elke CDN of statische bestandsserver ``` ## Conclusie Nuxt 3 biedt uitzonderlijke flexibiliteit voor het renderen van Vue.js-applicaties. De keuze tussen SSR, SSG en hybride rendering hangt af van de specifieke behoeften van elk project. **Belangrijkste punten:** ✅ **SSR**: ideaal voor dynamische content die goede SEO vereist (e-commerce, nieuwssites) ✅ **SSG**: perfect voor stabiele content (blogs, documentatie, marketingsites) ✅ **Hybride**: de beste aanpak voor complexe applicaties met uiteenlopende behoeften ✅ **useFetch/useAsyncData**: automatische hydratatie en cachebeheer ✅ **routeRules**: fijnmazige configuratie voor het gedrag van elke route ✅ **Caching**: meerdere strategieën om productieperformance te optimaliseren Hybride rendering combineren met een doordachte cachestrategie maakt het mogelijk performante applicaties te bouwen die voor SEO geoptimaliseerd zijn en tegelijk de interactiviteit van Single Page Applications behouden. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/vue-nuxt/nuxt-3-ssr-static-generation