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 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.
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:
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.
// 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:
// 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.
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:
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.
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:
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.
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.
<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.
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:
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:
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.
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:
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:
# Build voor productie
npm run build
# Start de server
node .output/server/index.mjsNuxt 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.contextobject 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 defineCachedEventHandlerbiedt route-level caching met invalidatie controls- Nitro presets maken zero-config deployment mogelijk naar Vercel, Netlify, Cloudflare en Node.js servers
Delen
Gerelateerde artikelen

Vue 3 met TypeScript in 2026: type-safe props, emits en composables
Type-safe Vue 3-componenten beheersen met TypeScript: generieke defineProps, defineEmits als tuple, getypeerde composables, defineModel en InjectionKey, plus sollicitatievragen.

Vue 3 testen in 2026: Vitest, Vue Test Utils en interviewvragen
Een praktische gids voor het testen van Vue in 2026: Vitest configureren, componenten mounten met Vue Test Utils, composables en Pinia-stores testen, API's mocken, coverage meten en de interviewvragen die teams stellen.

Vue 3-prestaties in 2026: Vapor Mode, Alien Signals en het einde van het Virtual DOM
Diepgaande analyse van de prestaties van Vue 3.6 Vapor Mode: hoe het het Virtual DOM uitschakelt, het Alien Signals-reactiviteitssysteem, benchmarks tegen Solid.js en praktische optimalisatietechnieken voor productie-apps.