Nuxt Nitro en Server Routes in 2026: Full-Stack Vue met API-Endpoints

Uitgebreide handleiding voor Nuxt Nitro Server Routes: API-endpoints maken, middleware implementeren, database-integratie en deployment-strategieën voor full-stack Vue-applicaties.

Nuxt Nitro en Server Routes in 2026: Full-Stack Vue met API-Endpoints

Nuxt Nitro transformeert Vue-applicaties tot krachtige full-stack oplossingen door een universele server-engine te bieden die API-routes, middleware en server-side logica naast frontend-componenten verwerkt. Met Nuxt 4.3 en de aankomende Nitro v3 is het bouwen van productie-klare backends nog nooit zo geïntegreerd geweest met Vue-ontwikkeling.

Full-Stack in Eén Repository

Nitro maakt gedeelde TypeScript-types tussen frontend en backend mogelijk, waardoor API-contract drift wordt geëlimineerd en boilerplate wordt verminderd. Server routes bevinden zich in server/api/ en worden automatisch beschikbaar op /api/* endpoints.

De Architectuur van Nuxt Nitro Server Engine Begrijpen

Nitro dient als de universele JavaScript server runtime die de server directory van Nuxt aandrijft. Anders dan traditionele Node.js servers compileert Nitro naar platform-geoptimaliseerde bundles die naadloos deployen naar Vercel, Netlify, Cloudflare Workers en standaard Node.js omgevingen zonder codewijzigingen.

De architectuur scheidt verantwoordelijkheden door directory-conventies:

server/api/users.get.tstypescript
export default defineEventHandler(async (event) => {
  // Nitro serialiseert return values automatisch naar JSON
  // HTTP method suffix (.get.ts) beperkt tot GET requests
  const users = await getUsersFromDatabase()
  return { users, count: users.length }
})

Nitro scant vier directories: server/api voor API-routes met /api prefix, server/routes voor routes zonder prefix, server/middleware voor request interceptors, en server/utils voor gedeelde server utilities. Bestanden buiten deze directories blijven onzichtbaar voor de server runtime.

RESTful API-Endpoints Maken met defineEventHandler

Server routes volgen file-based routing conventies waarbij bestandsnamen direct mappen naar URL-paden. HTTP method suffixen bepalen welke requests elke handler accepteert.

server/api/products/[id].get.tstypescript
// Verwerkt GET /api/products/123
export default defineEventHandler(async (event) => {
  // Route parameter uit URL extraheren
  const id = getRouterParam(event, 'id')
  
  if (!id) {
    throw createError({
      status: 400, // Nuxt 4 gebruikt Web API naamgeving (niet statusCode)
      statusText: 'Product ID required' // Niet statusMessage
    })
  }
  
  const product = await fetchProduct(id)
  
  if (!product) {
    throw createError({
      status: 404,
      statusText: 'Product not found'
    })
  }
  
  return product
})

Nuxt 4 adopteert Web API naamgevingsconventies ter voorbereiding op Nitro v3. De statusCode property wordt status, en statusMessage wordt statusText. Hoewel legacy properties blijven werken, garandeert migratie naar de nieuwe naamgeving forward-compatibiliteit met Nuxt 5.

POST requests met body validatie verwerken:

server/api/products/index.post.tstypescript
// Verwerkt POST /api/products
import { z } from 'zod'

const ProductSchema = z.object({
  name: z.string().min(1).max(200),
  price: z.number().positive(),
  category: z.enum(['electronics', 'clothing', 'food'])
})

export default defineEventHandler(async (event) => {
  // readBody parsed JSON automatisch
  const body = await readBody(event)
  
  // Valideren met Zod schema
  const result = ProductSchema.safeParse(body)
  
  if (!result.success) {
    throw createError({
      status: 422,
      statusText: 'Validation failed',
      data: result.error.flatten()
    })
  }
  
  const product = await createProduct(result.data)
  
  // 201 Created status instellen voor resource creatie
  setResponseStatus(event, 201)
  return product
})

Server Middleware voor Authenticatie en Logging

Middleware bestanden worden uitgevoerd vóór route handlers, wat cross-cutting concerns zoals authenticatie, logging en request transformatie mogelijk maakt. Anders dan route handlers retourneren middleware geen responses direct.

server/middleware/auth.tstypescript
export default defineEventHandler(async (event) => {
  // Auth overslaan voor publieke routes
  const publicRoutes = ['/api/health', '/api/auth/login']
  if (publicRoutes.includes(event.path)) {
    return // Doorgaan naar volgende handler
  }
  
  const authHeader = getHeader(event, 'authorization')
  
  if (!authHeader?.startsWith('Bearer ')) {
    throw createError({
      status: 401,
      statusText: 'Authentication required'
    })
  }
  
  const token = authHeader.slice(7)
  
  try {
    // JWT verifiëren en user aan event context koppelen
    const user = await verifyToken(token)
    event.context.user = user
  } catch {
    throw createError({
      status: 401,
      statusText: 'Invalid or expired token'
    })
  }
})

Het event.context object blijft behouden over middleware en handlers binnen een enkele request, wat een type-safe manier biedt om data te delen. Context types worden gedefinieerd in een declaratiebestand:

server/types/context.d.tstypescript
declare module 'h3' {
  interface H3EventContext {
    user?: {
      id: string
      email: string
      role: 'admin' | 'user'
    }
  }
}

Voor voorbereiding op sollicitatiegesprekken over Nuxt server concepten, bekijk de Nuxt Server Routes interviewvragen module.

Klaar om je Vue.js / Nuxt.js gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

Database-Integratie met Prisma en Server Utils

Server utilities in server/utils/ worden automatisch geïmporteerd in alle server code, waardoor database clients en gedeelde logica toegankelijk worden zonder expliciete imports.

server/utils/db.tstypescript
import { PrismaClient } from '@prisma/client'

// Singleton pattern voorkomt meerdere instanties in development
const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}

export const prisma = globalForPrisma.prisma ?? new PrismaClient({
  log: process.env.NODE_ENV === 'development' 
    ? ['query', 'error', 'warn'] 
    : ['error']
})

if (process.env.NODE_ENV !== 'production') {
  globalForPrisma.prisma = prisma
}

Met de database client globaal beschikbaar, hebben route handlers direct toegang:

server/api/posts/index.get.tstypescript
export default defineEventHandler(async (event) => {
  // Query parameters voor paginatie
  const query = getQuery(event)
  const page = Number(query.page) || 1
  const limit = Math.min(Number(query.limit) || 10, 100)
  const skip = (page - 1) * limit
  
  // Parallelle queries voor data en count
  const [posts, total] = await Promise.all([
    prisma.post.findMany({
      skip,
      take: limit,
      orderBy: { createdAt: 'desc' },
      include: { author: { select: { name: true, avatar: true } } }
    }),
    prisma.post.count()
  ])
  
  return {
    posts,
    pagination: {
      page,
      limit,
      total,
      pages: Math.ceil(total / limit)
    }
  }
})

Server Plugins voor Runtime Initialisatie

Server plugins in server/plugins/ worden eenmalig uitgevoerd wanneer de server start, ideaal voor het initialiseren van verbindingen, het plannen van taken of het opzetten van monitoring.

server/plugins/database.tstypescript
export default defineNitroPlugin(async (nitroApp) => {
  // Database verbinding verifiëren bij opstarten
  try {
    await prisma.$connect()
    console.log('Database connected successfully')
  } catch (error) {
    console.error('Database connection failed:', error)
    process.exit(1) // Snel falen als DB niet beschikbaar is
  }
  
  // Graceful shutdown hook
  nitroApp.hooks.hook('close', async () => {
    await prisma.$disconnect()
    console.log('Database disconnected')
  })
})

Het plugin systeem integreert met Nitro hooks voor lifecycle management. Hooks worden geactiveerd op specifieke punten: request voor verwerking, beforeResponse voor verzending, en close tijdens shutdown.

Type-Safe API-Calls vanuit Vue Componenten

Nuxts $fetch utility biedt type-inferentie van server routes bij gebruik van de ~/server alias. Gecombineerd met de useFetch composable, consumeren componenten APIs met volledige TypeScript ondersteuning.

vue
<script setup lang="ts">
// Geïnfereerd return type van server/api/products/[id].get.ts
const route = useRoute()
const { data: product, status, error } = await useFetch(
  `/api/products/${route.params.id}`
)

// Mutatie met optimistische updates
const { execute: updateProduct, status: updateStatus } = useFetch(
  `/api/products/${route.params.id}`,
  {
    method: 'PATCH',
    immediate: false, // Niet fetchen bij mount
    watch: false // Niet re-fetchen bij dependency wijziging
  }
)

async function handleUpdate(updates: Partial<Product>) {
  await updateProduct({ body: updates })
  // Re-fetch om state te synchroniseren
  await refreshNuxtData(`product-${route.params.id}`)
}
</script>

<template>
  <div v-if="status === 'pending'">Loading...</div>
  <div v-else-if="error">{{ error.message }}</div>
  <ProductDetail v-else :product="product" @update="handleUpdate" />
</template>

Caching Strategieën voor Server Routes

Nuxt 4.3 introduceert verbeterde caching controls via routeRules in nuxt.config.ts. Server routes profiteren van dezelfde caching infrastructuur als paginas.

nuxt.config.tstypescript
export default defineNuxtConfig({
  routeRules: {
    // Cache productlijsten voor 5 minuten
    '/api/products': { 
      cache: { 
        maxAge: 300,
        staleMaxAge: 600, // Serve stale tijdens revalidatie
        swr: true 
      } 
    },
    // Geen cache voor user-specifieke data
    '/api/user/**': { cache: false },
    // Pre-render statische API responses tijdens build time
    '/api/categories': { prerender: true }
  }
})

Voor dynamische cache invalidatie wordt de defineCachedEventHandler wrapper gebruikt:

server/api/trending.get.tstypescript
export default defineCachedEventHandler(async (event) => {
  const trending = await calculateTrendingProducts()
  return trending
}, {
  maxAge: 60 * 5, // 5 minuten
  name: 'trending-products',
  getKey: () => 'trending', // Cache key voor invalidatie
  shouldBypassCache: (event) => {
    // Bypass voor admin gebruikers
    return event.context.user?.role === 'admin'
  }
})

Error Handling en Response Formattering

Consistente error responses verbeteren de API bruikbaarheid. Een gedeelde error handler utility maken:

server/utils/errors.tstypescript
import { H3Error } from 'h3'

export function handleDatabaseError(error: unknown): never {
  console.error('Database error:', error)
  
  // Prisma-specifieke error handling
  if (error instanceof Error && 'code' in error) {
    const prismaError = error as { code: string }
    
    if (prismaError.code === 'P2002') {
      throw createError({
        status: 409,
        statusText: 'Resource already exists'
      })
    }
    
    if (prismaError.code === 'P2025') {
      throw createError({
        status: 404,
        statusText: 'Resource not found'
      })
    }
  }
  
  throw createError({
    status: 500,
    statusText: 'Internal server error'
  })
}

Voor uitgebreide Vue.js patterns en state management, bekijk het artikel Pinia vs Vuex vergelijking.

Productie Checklist

Voor het deployen van Nitro servers: valideer environment variables met Zod schemas, implementeer rate limiting middleware, voeg request logging toe voor debugging, en configureer CORS headers voor cross-origin API toegang.

Deployment Across Platforms

Nitros preset systeem genereert geoptimaliseerde builds voor elk platform:

nuxt.config.tstypescript
export default defineNuxtConfig({
  nitro: {
    // Automatisch gedetecteerd op Vercel/Netlify, of handmatig specificeren
    preset: 'node-server', // 'vercel', 'netlify', 'cloudflare-workers'
    
    // Responses comprimeren
    compressPublicAssets: true,
    
    // Externe packages niet bundlen
    externals: {
      external: ['@prisma/client']
    }
  }
})

Voor Node.js deployments bevat de output een standalone server:

bash
# Build voor productie
npm run build

# Start de server
node .output/server/index.mjs
Nuxt 3 End of Life

Nuxt 3 bereikt end-of-life op 31 juli 2026. Projecten moeten migreren naar Nuxt 4 met de officiële migratiegids. Nuxt 5 met Nitro v3 volgt kort daarna.

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Conclusie

  • Server routes in server/api/ mappen automatisch naar /api/* endpoints met HTTP method suffixen (.get.ts, .post.ts) die request types bepalen
  • Middleware in server/middleware/ handelt authenticatie, logging en request transformatie af voordat routes worden uitgevoerd
  • Het event.context object deelt getypeerde data tussen middleware en handlers binnen een request
  • Server utils in server/utils/ worden automatisch geïmporteerd in server code, ideaal voor database clients en gedeelde logica
  • Nuxt 4 adopteert Web API naamgeving (status/statusText) ter voorbereiding op Nitro v3
  • defineCachedEventHandler biedt route-level caching met invalidatie controls
  • Nitro presets maken zero-config deployment mogelijk naar Vercel, Netlify, Cloudflare en Node.js servers

Delen

Gerelateerde artikelen