# Nuxt Nitro dan Server Routes di 2026: Full-Stack Vue dan API Endpoints > Pelajari cara menguasai Nuxt Nitro server routes untuk membangun aplikasi Vue full-stack. Tutorial lengkap API endpoints, middleware, integrasi database, dan deployment production dengan Nuxt 4. - Published: 2026-07-16 - Updated: 2026-07-16 - Author: SharpSkill - Tags: nuxt, nitro, vue, full-stack, api, server-routes - Reading time: 12 min --- Nuxt Nitro mengubah aplikasi Vue menjadi platform full-stack yang powerful dengan menyediakan engine server universal yang menangani API routes, middleware, dan logika server-side bersamaan dengan komponen frontend. Dengan Nuxt 4.3 dan Nitro v3 yang akan datang, membangun backend siap-production tidak pernah semudah ini terintegrasi dengan pengembangan Vue. > **Full-Stack dalam Satu Repository** > > Nitro memungkinkan berbagi tipe TypeScript antara frontend dan backend, menghilangkan perbedaan kontrak API dan mengurangi boilerplate. Server routes berada di `server/api/` dan otomatis tersedia di endpoint `/api/*`. ## Memahami Arsitektur Nuxt Nitro Server Engine Nitro berfungsi sebagai runtime server JavaScript universal yang menggerakkan direktori server Nuxt. Berbeda dengan server Node.js tradisional, Nitro mengkompilasi menjadi bundle yang dioptimalkan untuk platform dan dapat di-deploy dengan mulus ke [Vercel](https://vercel.com/docs/frameworks/nuxt), [Netlify](https://docs.netlify.com/frameworks/nuxt/), Cloudflare Workers, dan lingkungan Node.js standar tanpa perubahan kode. Arsitekturnya memisahkan concerns melalui konvensi direktori: ```typescript // server/api/users.get.ts export default defineEventHandler(async (event) => { // Nitro auto-serializes return values to JSON // HTTP method suffix (.get.ts) restricts to GET requests const users = await getUsersFromDatabase() return { users, count: users.length } }) ``` Nitro memindai empat direktori: `server/api` untuk API routes dengan prefix `/api`, `server/routes` untuk routes tanpa prefix, `server/middleware` untuk request interceptors, dan `server/utils` untuk shared server utilities. File di luar direktori ini tetap tidak terlihat oleh server runtime. ## Membuat RESTful API Endpoints dengan defineEventHandler Server routes mengikuti konvensi file-based routing dimana nama file langsung dipetakan ke URL paths. Suffix HTTP method mengontrol request mana yang diterima setiap handler. ```typescript // server/api/products/[id].get.ts // Handles GET /api/products/123 export default defineEventHandler(async (event) => { // Extract route parameter from URL const id = getRouterParam(event, 'id') if (!id) { throw createError({ status: 400, // Nuxt 4 uses Web API naming (not statusCode) statusText: 'Product ID required' // Not statusMessage }) } const product = await fetchProduct(id) if (!product) { throw createError({ status: 404, statusText: 'Product not found' }) } return product }) ``` Nuxt 4 mengadopsi konvensi penamaan Web API sebagai persiapan untuk Nitro v3. Property `statusCode` menjadi `status`, dan `statusMessage` menjadi `statusText`. Meskipun property lama masih berfungsi, migrasi ke penamaan baru memastikan kompatibilitas dengan Nuxt 5. Menangani POST requests dengan validasi body: ```typescript // server/api/products/index.post.ts // Handles 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 automatically parses JSON const body = await readBody(event) // Validate with 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) // Set 201 Created status for resource creation setResponseStatus(event, 201) return product }) ``` ## Server Middleware untuk Autentikasi dan Logging File middleware dieksekusi sebelum route handlers, memungkinkan cross-cutting concerns seperti autentikasi, logging, dan transformasi request. Berbeda dengan route handlers, middleware tidak mengembalikan response secara langsung. ```typescript // server/middleware/auth.ts export default defineEventHandler(async (event) => { // Skip auth for public routes const publicRoutes = ['/api/health', '/api/auth/login'] if (publicRoutes.includes(event.path)) { return // Continue to next handler } const authHeader = getHeader(event, 'authorization') if (!authHeader?.startsWith('Bearer ')) { throw createError({ status: 401, statusText: 'Authentication required' }) } const token = authHeader.slice(7) try { // Verify JWT and attach user to event context const user = await verifyToken(token) event.context.user = user } catch { throw createError({ status: 401, statusText: 'Invalid or expired token' }) } }) ``` Objek `event.context` bertahan di seluruh middleware dan handlers dalam satu request, menyediakan cara type-safe untuk berbagi data. Definisikan tipe context dalam file deklarasi: ```typescript // server/types/context.d.ts declare module 'h3' { interface H3EventContext { user?: { id: string email: string role: 'admin' | 'user' } } } ``` Untuk persiapan wawancara tentang konsep Nuxt server, tinjau modul [pertanyaan wawancara Nuxt Server Routes](/technologies/vue-nuxt/interview-questions/nuxt-server-routes). ## Integrasi Database dengan Prisma dan Server Utils Server utilities di `server/utils/` auto-import di seluruh kode server, membuat database clients dan logika bersama dapat diakses tanpa import eksplisit. ```typescript // server/utils/db.ts import { PrismaClient } from '@prisma/client' // Singleton pattern prevents multiple instances 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 } ``` Dengan database client tersedia secara global, route handlers dapat mengaksesnya langsung: ```typescript // server/api/posts/index.get.ts export default defineEventHandler(async (event) => { // Query parameters for pagination const query = getQuery(event) const page = Number(query.page) || 1 const limit = Math.min(Number(query.limit) || 10, 100) const skip = (page - 1) * limit // Parallel queries for data and 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 untuk Inisialisasi Runtime Server plugins di `server/plugins/` dieksekusi sekali saat server dimulai, ideal untuk menginisialisasi koneksi, menjadwalkan tasks, atau menyiapkan monitoring. ```typescript // server/plugins/database.ts export default defineNitroPlugin(async (nitroApp) => { // Verify database connection on startup try { await prisma.$connect() console.log('Database connected successfully') } catch (error) { console.error('Database connection failed:', error) process.exit(1) // Fail fast if DB unavailable } // Graceful shutdown hook nitroApp.hooks.hook('close', async () => { await prisma.$disconnect() console.log('Database disconnected') }) }) ``` Sistem plugin terintegrasi dengan [Nitro hooks](https://nitro.unjs.io/guide/plugins) untuk lifecycle management. Hooks diaktifkan pada titik tertentu: `request` sebelum handling, `beforeResponse` sebelum mengirim, dan `close` saat shutdown. ## Panggilan API Type-Safe dari Vue Components Utility `$fetch` Nuxt menyediakan type inference dari server routes saat menggunakan alias `~/server`. Dikombinasikan dengan [composable useFetch](/technologies/vue-nuxt/interview-questions/nuxt-data-fetching), komponen mengkonsumsi API dengan dukungan TypeScript penuh. ```vue ``` ## Strategi Caching untuk Server Routes Nuxt 4.3 memperkenalkan kontrol caching yang ditingkatkan melalui `routeRules` di `nuxt.config.ts`. Server routes mendapat manfaat dari infrastruktur caching yang sama seperti pages. ```typescript // nuxt.config.ts export default defineNuxtConfig({ routeRules: { // Cache product listings for 5 minutes '/api/products': { cache: { maxAge: 300, staleMaxAge: 600, // Serve stale while revalidating swr: true } }, // No cache for user-specific data '/api/user/**': { cache: false }, // Pre-render static API responses at build time '/api/categories': { prerender: true } } }) ``` Untuk invalidasi cache dinamis, gunakan wrapper `defineCachedEventHandler`: ```typescript // server/api/trending.get.ts export default defineCachedEventHandler(async (event) => { const trending = await calculateTrendingProducts() return trending }, { maxAge: 60 * 5, // 5 minutes name: 'trending-products', getKey: () => 'trending', // Cache key for invalidation shouldBypassCache: (event) => { // Bypass for admin users return event.context.user?.role === 'admin' } }) ``` ## Penanganan Error dan Format Response Response error yang konsisten meningkatkan usability API. Buat utilitas error handler bersama: ```typescript // server/utils/errors.ts import { H3Error } from 'h3' export function handleDatabaseError(error: unknown): never { console.error('Database error:', error) // Prisma-specific 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' }) } ``` Untuk pola Vue.js yang komprehensif dan state management, jelajahi artikel [perbandingan Pinia vs Vuex](/blog/vue-nuxt/vue-3-pinia-vs-vuex-state-management). > **Checklist Production** > > Sebelum men-deploy Nitro servers: validasi environment variables dengan skema Zod, implementasikan rate limiting middleware, tambahkan request logging untuk debugging, dan konfigurasi CORS headers untuk akses API cross-origin. ## Deployment Lintas Platform Sistem preset Nitro menghasilkan build yang dioptimalkan untuk setiap platform: ```typescript // nuxt.config.ts export default defineNuxtConfig({ nitro: { // Auto-detected on Vercel/Netlify, or specify manually preset: 'node-server', // 'vercel', 'netlify', 'cloudflare-workers' // Compress responses compressPublicAssets: true, // External packages not to bundle externals: { external: ['@prisma/client'] } } }) ``` Untuk deployment Node.js, output mencakup server standalone: ```bash # Build for production npm run build # Start the server node .output/server/index.mjs ``` > **Nuxt 3 End of Life** > > Nuxt 3 mencapai end-of-life pada 31 Juli 2026. Proyek harus bermigrasi ke Nuxt 4 menggunakan [panduan migrasi resmi](https://nuxt.com/docs/getting-started/upgrade). Nuxt 5 dengan Nitro v3 menyusul segera setelahnya. ## Kesimpulan - Server routes di `server/api/` otomatis dipetakan ke endpoint `/api/*` dengan suffix HTTP method (`.get.ts`, `.post.ts`) mengontrol tipe request - Middleware di `server/middleware/` menangani autentikasi, logging, dan transformasi request sebelum routes dieksekusi - Objek `event.context` membagikan data yang di-type antara middleware dan handlers dalam satu request - Server utils di `server/utils/` auto-import di seluruh kode server, ideal untuk database clients dan logika bersama - Nuxt 4 mengadopsi penamaan Web API (`status`/`statusText`) sebagai persiapan untuk Nitro v3 - `defineCachedEventHandler` menyediakan caching level route dengan kontrol invalidasi - Preset Nitro memungkinkan deployment tanpa konfigurasi ke Vercel, Netlify, Cloudflare, dan server Node.js --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/vue-nuxt/nuxt-nitro-server-routes-2026