# Nuxt Nitro i Server Routes w 2026: Full-Stack Vue i API Endpoints
> Opanuj Nuxt Nitro server routes do budowania aplikacji full-stack Vue. Poznaj API endpoints, middleware, integrację z bazą danych oraz wzorce wdrożeń produkcyjnych z 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 przekształca aplikacje Vue w pełnoprawne rozwiązania full-stack, dostarczając uniwersalny silnik serwerowy obsługujący API routes, middleware oraz logikę serwerową obok komponentów frontendowych. Wraz z Nuxt 4.3 i nadchodzącym Nitro v3, budowanie produkcyjnych backendów nigdy nie było tak zintegrowane z rozwojem Vue.
> **Full-Stack w jednym repozytorium**
>
> Nitro umożliwia współdzielenie typów TypeScript między frontendem a backendem, eliminując rozbieżności kontraktów API i redukując boilerplate. Server routes znajdują się w `server/api/` i automatycznie stają się dostępne jako endpointy `/api/*`.
## Architektura silnika Nuxt Nitro Server
Nitro służy jako uniwersalne środowisko uruchomieniowe JavaScript zasilające katalog server w Nuxt. W przeciwieństwie do tradycyjnych serwerów Node.js, Nitro kompiluje do bundli zoptymalizowanych pod konkretne platformy, które wdrażają się bezproblemowo na [Vercel](https://vercel.com/docs/frameworks/nuxt), [Netlify](https://docs.netlify.com/frameworks/nuxt/), Cloudflare Workers oraz standardowe środowiska Node.js bez zmian w kodzie.
Architektura rozdziela odpowiedzialności poprzez konwencje katalogów:
```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 skanuje cztery katalogi: `server/api` dla API routes z prefiksem `/api`, `server/routes` dla routes bez prefiksu, `server/middleware` dla interceptorów żądań oraz `server/utils` dla współdzielonych narzędzi serwerowych. Pliki poza tymi katalogami pozostają niewidoczne dla środowiska serwerowego.
## Tworzenie RESTful API Endpoints z defineEventHandler
Server routes podążają za konwencjami routingu opartymi na plikach, gdzie nazwy plików mapują bezpośrednio na ścieżki URL. Sufiksy metod HTTP kontrolują, które żądania akceptuje każdy 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 przyjmuje konwencje nazewnictwa Web API w przygotowaniu do Nitro v3. Właściwość `statusCode` zmienia się na `status`, a `statusMessage` na `statusText`. Chociaż starsze właściwości nadal działają, migracja do nowego nazewnictwa zapewnia kompatybilność z Nuxt 5.
Obsługa żądań POST z walidacją 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 dla uwierzytelniania i logowania
Pliki middleware wykonują się przed handlerami tras, umożliwiając obsługę przekrojowych zagadnień takich jak uwierzytelnianie, logowanie i transformacja żądań. W przeciwieństwie do handlerów tras, middleware nie zwraca bezpośrednio odpowiedzi.
```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'
})
}
})
```
Obiekt `event.context` utrzymuje się między middleware a handlerami w ramach pojedynczego żądania, zapewniając typowo-bezpieczny sposób współdzielenia danych. Typy kontekstu definiuje się w pliku deklaracji:
```typescript
// server/types/context.d.ts
declare module 'h3' {
interface H3EventContext {
user?: {
id: string
email: string
role: 'admin' | 'user'
}
}
}
```
Do przygotowań do rozmów kwalifikacyjnych dotyczących koncepcji serwera Nuxt warto zapoznać się z modułem [pytań rekrutacyjnych o Nuxt Server Routes](/technologies/vue-nuxt/interview-questions/nuxt-server-routes).
## Integracja bazy danych z Prisma i Server Utils
Narzędzia serwerowe w `server/utils/` automatycznie importują się w całym kodzie serwerowym, czyniąc klienty baz danych i współdzieloną logikę dostępnymi bez jawnych importów.
```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
}
```
Z globalnie dostępnym klientem bazy danych, handlery tras uzyskują do niego bezpośredni dostęp:
```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 dla inicjalizacji runtime
Pluginy serwerowe w `server/plugins/` wykonują się raz podczas startu serwera, idealnie nadając się do inicjalizacji połączeń, planowania zadań lub konfiguracji monitoringu.
```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')
})
})
```
System pluginów integruje się z [hookami Nitro](https://nitro.unjs.io/guide/plugins) do zarządzania cyklem życia. Hooki uruchamiają się w określonych momentach: `request` przed obsługą, `beforeResponse` przed wysłaniem i `close` podczas zamykania.
## Typowo-bezpieczne wywołania API z komponentów Vue
Narzędzie `$fetch` w Nuxt zapewnia wnioskowanie typów z tras serwerowych przy użyciu aliasu `~/server`. W połączeniu z [composable useFetch](/technologies/vue-nuxt/interview-questions/nuxt-data-fetching), komponenty konsumują API z pełnym wsparciem TypeScript.
```vue
Loading...
{{ error.message }}
```
## Strategie cachowania dla Server Routes
Nuxt 4.3 wprowadza ulepszone kontrole cachowania poprzez `routeRules` w `nuxt.config.ts`. Server routes korzystają z tej samej infrastruktury cachowania co strony.
```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 }
}
})
```
Dla dynamicznej inwalidacji cache należy użyć wrappera `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'
}
})
```
## Obsługa błędów i formatowanie odpowiedzi
Spójne odpowiedzi błędów poprawiają użyteczność API. Należy utworzyć współdzielone narzędzie do obsługi błędów:
```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'
})
}
```
Dla kompleksowych wzorców Vue.js i zarządzania stanem warto zapoznać się z artykułem [porównanie Pinia vs Vuex](/blog/vue-nuxt/vue-3-pinia-vs-vuex-state-management).
> **Checklista produkcyjna**
>
> Przed wdrożeniem serwerów Nitro należy: zwalidować zmienne środowiskowe schematami Zod, zaimplementować middleware rate limiting, dodać logowanie żądań do debugowania oraz skonfigurować nagłówki CORS dla cross-origin dostępu do API.
## Wdrożenie na różnych platformach
System presetów Nitro generuje zoptymalizowane buildy dla każdej platformy:
```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']
}
}
})
```
Dla wdrożeń Node.js, output zawiera samodzielny serwer:
```bash
# Build for production
npm run build
# Start the server
node .output/server/index.mjs
```
> **Koniec wsparcia dla Nuxt 3**
>
> Nuxt 3 osiąga koniec wsparcia 31 lipca 2026. Projekty powinny migrować do Nuxt 4 używając [oficjalnego przewodnika migracji](https://nuxt.com/docs/getting-started/upgrade). Nuxt 5 z Nitro v3 pojawi się wkrótce potem.
## Podsumowanie
- Server routes w `server/api/` automatycznie mapują się na endpointy `/api/*` z sufiksami metod HTTP (`.get.ts`, `.post.ts`) kontrolującymi typy żądań
- Middleware w `server/middleware/` obsługuje uwierzytelnianie, logowanie i transformację żądań przed wykonaniem tras
- Obiekt `event.context` współdzieli typowane dane między middleware a handlerami w ramach żądania
- Narzędzia serwerowe w `server/utils/` automatycznie importują się w kodzie serwerowym, idealnie dla klientów baz danych i współdzielonej logiki
- Nuxt 4 przyjmuje nazewnictwo Web API (`status`/`statusText`) w przygotowaniu do Nitro v3
- `defineCachedEventHandler` zapewnia cachowanie na poziomie tras z kontrolami inwalidacji
- Presety Nitro umożliwiają bezproblemowe wdrożenia na Vercel, Netlify, Cloudflare i serwery Node.js
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/pl/blog/vue-nuxt/nuxt-nitro-server-routes-2026