Als ich meine erste Produktions-API erstellte, verwendete ich Express.js, und die Einrichtung dauerte etwa zwei Stunden: Boilerplate, Middleware, Route-Handler, TypeScript-Konfiguration und Bereitstellungsskripte. Vor Kurzem habe ich mit NitroJs eine komplette REST-API in nur 20 Minuten ausgeliefert. Keine app.use()-Ketten, kein manuelles Routing, keine Bereitstellungsprobleme.
Dieser Leitfaden zeigt Ihnen, wie NitroJs Boilerplate eliminiert und Ihnen gleichzeitig ein produktionsreifes Backend bietet, das überall läuft: Node, Bun, Deno, serverless oder am Edge.
Was ist NitroJs und warum sollte man es für Backend-APIs verwenden?
NitroJs ist ein Server-Toolkit aus dem UnJS-Ökosystem, das Ihr Backend als Build-Artefakt behandelt. Anstatt einen Server zu schreiben, der an eine Runtime gebunden ist, schreiben Sie Route-Handler, und Nitro kompiliert sie zu einem portablen Bundle. Stellen Sie denselben Code auf Node.js, Cloudflare Workers, Vercel oder einem Docker-Container bereit, ohne eine einzige Zeile zu ändern.

Zentrales Denkmodell: Schreiben Sie Routen, keine Server. Sie konzentrieren sich auf die API-Logik; Nitro kümmert sich um HTTP, Middleware und die Plattform-Verbindung.
Wesentliche Vorteile für Backend-APIs:
- Zero Config: Keine
server.js-Boilerplate - Dateisystem-Routing:
routes/users.get.tswird zuGET /users - TypeScript-nativ: Automatisch abgeleitete Typen von Handlern
- Universelle Bereitstellung: Ein Build, mehrere Ziele
- Eingebautes Caching: API-Antworten im Speicher, Redis oder Cloudflare KV speichern
- Speicherschicht: Abstrahiertes Dateisystem für temporäre Daten
Für API-Entwickler bedeutet dies, dass Sie schneller liefern und weniger refaktorisieren müssen, wenn sich die Infrastruktur ändert.
Erste Schritte: NitroJs in 5 Minuten installieren
Schritt 1: Ein Projekt gerüsten
# Using pnpm (recommended)
pnpm dlx giget@latest nitro nitro-api-backend
# Or npm
npm create nitro@latest nitro-api-backend
# Or bun
bunx giget@latest nitro nitro-api-backend
Dies klont die offizielle Starter-Vorlage in nitro-api-backend.
Schritt 2: Die Struktur erkunden
cd nitro-api-backend
tree -L 2
Ausgabe:
├── server
│ ├── api
│ ├── routes
│ ├── tasks
│ └── middleware
├── nitro.config.ts
├── package.json
└── tsconfig.json
Wichtige Verzeichnisse:
server/api/: API-Routen (keine UI)server/routes/: Full-Stack-Routen (für SSR)server/middleware/: Globale Middlewareserver/tasks/: Hintergrundaufgaben
Für eine reine Backend-API ignorieren Sie routes und legen alles in api ab.
Schritt 3: Entwicklungsserver starten
pnpm install
pnpm dev
Nitro startet unter http://localhost:3000 mit Hot-Reload. Bearbeiten Sie eine Datei, und der Server startet in weniger als 200 ms neu.

Ihren ersten API-Endpunkt erstellen
Einfacher GET-Handler
Erstellen Sie server/api/users.get.ts:
// server/api/users.get.ts
export default defineEventHandler(() => {
return [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
];
});
Nitro stellt dies automatisch unter GET /api/users bereit. Der defineEventHandler-Wrapper bietet Typsicherheit und Zugriff auf den Request-Kontext.
Dynamische Route mit Parametern
Erstellen Sie server/api/users/[id].get.ts:
// server/api/users/[id].get.ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id');
if (!id) {
throw createError({
statusCode: 400,
statusMessage: 'User ID is required'
});
}
return {
id: Number(id),
name: `User ${id}`,
email: `user${id}@example.com`
};
});
Greifen Sie auf GET /api/users/42 zu, um { id: 42, name: "User 42", ... } zu sehen.
POST mit JSON-Body
Erstellen Sie server/api/users.post.ts:
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
// Nitro parst JSON automatisch
const { name, email } = body;
if (!name || !email) {
throw createError({
statusCode: 422,
statusMessage: 'Name and email are required'
});
}
// Datenbank-Einfügung simulieren
const newUser = {
id: Math.floor(Math.random() * 1000),
name,
email,
createdAt: new Date().toISOString()
};
return newUser;
});
Testen Sie es:
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","email":"charlie@example.com"}'
Typ-sichere Antworten
Nitro leitet Antworttypen aus Ihren Rückgabewerten ab. Für strikte Verträge verwenden Sie explizite Typen:
// server/api/products.get.ts
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
export default defineEventHandler<Product[]>(() => {
return [
{ id: 1, name: "Laptop", price: 1299.99, inStock: true },
{ id: 2, name: "Mouse", price: 29.99, inStock: false }
];
});
Clients, die diesen Endpunkt importieren, erhalten nun vollen IntelliSense.
Fortgeschrittene API-Muster
Middleware für Authentifizierung
Erstellen Sie server/middleware/auth.ts:
// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
const protectedRoutes = ['/api/admin', '/api/users/me'];
if (protectedRoutes.some(route => event.path.startsWith(route))) {
const token = getHeader(event, 'authorization')?.replace('Bearer ', '');
if (!token || token !== process.env.API_SECRET) {
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized'
});
}
}
});
Middleware wird vor jeder Route ausgeführt. Fügen Sie sie zu nitro.config.ts hinzu:
// nitro.config.ts
export default defineNitroConfig({
srcDir: 'server',
runtimeConfig: {
apiSecret: process.env.API_SECRET
}
});
Caching von API-Antworten
Berechnungen, die viel Zeit in Anspruch nehmen, für 60 Sekunden cachen:
// server/api/stats.get.ts
export default defineCachedEventHandler(async () => {
const db = useStorage('data');
const users = await db.getItem('users') || [];
return {
totalUsers: users.length,
activeUsers: users.filter(u => u.lastSeen > Date.now() - 86400000).length
};
}, {
maxAge: 60, // Sekunden
name: 'stats',
getKey: () => 'global-stats'
});
Nitro übernimmt die Cache-Invalidierung und Speicherung (Speicher, Redis oder Cloudflare KV, je nach Bereitstellungsziel).
Dateiupload-Verwaltung
// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
const files = await readMultipartFormData(event);
if (!files?.length) {
throw createError({ statusCode: 400, statusMessage: 'Keine Dateien hochgeladen' });
}
const storage = useStorage('uploads');
const file = files[0];
await storage.setItem(file.filename, file.data);
return { success: true, filename: file.filename };
});
Testen mit:
curl -X POST http://localhost:3000/api/upload \
-F "file=@/path/to/image.jpg"
Bereitstellung: Vom lokalen System zur Produktion
Für die Produktion bauen
pnpm build
Nitro generiert ein .output-Verzeichnis mit plattformspezifischen Einstiegspunkten.
Auf Node.js ausführen
node .output/server/index.mjs
Keine node_modules erforderlich – der Build bündelt alles.
Auf Cloudflare Workers bereitstellen
# Preset installieren
pnpm add -D nitro-preset-cloudflare-workers
# Mit Preset bauen
NITRO_PRESET=cloudflare-workers pnpm build
# Bereitstellen
wrangler deploy .output
Auf Vercel bereitstellen (Serverless)
# Vercel erkennt Nitro automatisch
vercel
Oder konfigurieren Sie nitro.config.ts:
export default defineNitroConfig({
preset: 'vercel-edge'
});
Umgebungsvariablen
Erstellen Sie .env lokal und verwenden Sie dann in der Produktion Plattform-Dashboards:
# .env
API_SECRET=dev-secret-key
DATABASE_URL=file:./dev.db
Zugriff in Handlern:
const config = useRuntimeConfig();
const secret = config.apiSecret;
Fortgeschrittene Anwendungsfälle
WebSockets & Server-Sent Events
Nitro unterstützt WebSockets über defineWebSocketHandler:
// server/api/ws.ts
export default defineWebSocketHandler({
open(peer) {
console.log('WebSocket verbunden:', peer);
},
message(peer, message) {
peer.send(`Echo: ${message.text()}`);
},
close(peer, details) {
console.log('WebSocket geschlossen:', details);
}
});
Zugriff unter ws://localhost:3000/api/ws.
Hintergrundaufgaben
Erstellen Sie server/tasks/cleanup.ts:
// server/tasks/cleanup.ts
export default defineCronHandler('0 2 * * *', async () => {
const db = useStorage('temp');
const keys = await db.getKeys();
for (const key of keys) {
const metadata = await db.getMeta(key);
if (metadata.expiresAt < Date.now()) {
await db.removeItem(key);
}
}
console.log('Bereinigung abgeschlossen');
});
Dies läuft täglich um 2 Uhr morgens. Stellen Sie es auf einer Plattform mit Cron-Unterstützung bereit (z.B. Vercel, Netlify).
Workflow-Engines
Integration mit useWorkflow.dev für komplexe Orchestrierung:
// server/api/workflows/process.ts
import { createWorkflow } from '@useworkflow/sdk';
export default defineEventHandler(async (event) => {
const workflow = createWorkflow('data-pipeline', {
steps: [
{ id: 'fetch', run: 'https://api.example.com/data' },
{ id: 'transform', run: 'transform.js' },
{ id: 'store', run: async (data) => {
const storage = useStorage('results');
await storage.setItem('latest', data);
}}
]
});
await workflow.start();
return { status: 'gestartet' };
});
Reale Entwicklerszenarien
Szenario 1: Backend für statische Websites
Stellen Sie eine Nitro-API auf Cloudflare Workers bereit, die JSON-Daten für eine statische JAMstack-Website liefert. Der kostenlose Tarif deckt 100.000 Anfragen/Tag ab.
Szenario 2: Mobile App API
Erstellen Sie REST-Endpunkte für eine React Native App. Nutzen Sie die integrierte CORS-Verwaltung von Nitro:
// nitro.config.ts
export default defineNitroConfig({
routeRules: {
'/api/**': { cors: true }
}
});
Szenario 3: Microservices Gateway
Führen Sie Nitro als API-Gateway aus, das Microservices aggregiert. Verwenden Sie $fetch zum Proxy von Anfragen:
// server/api/aggregate.get.ts
export default defineEventHandler(async (event) => {
const [users, posts] = await Promise.all([
$fetch('https://users-service.internal/users'),
$fetch('https://posts-service.internal/posts')
]);
return { users, posts };
});
Testen Sie Ihre NitroJs-APIs mit Apidog
Nitro generiert Backends schnell, aber Geschwindigkeit bedeutet nichts, wenn Ihre Endpunkte kaputtgehen. Wenn Sie einen neuen POST /api/users bereitstellen, importieren Sie die Routendefinition in Apidog. Es rekonstruiert den Rückgabetyp Ihres Handlers und generiert automatisch Vertragstests.

Führen Sie sie in CI aus, um Breaking Changes abzufangen, bevor Ihr Frontend-Team die Nerven verliert. Der Start ist kostenlos, und es ist die Leitplanke, die Ihre schnelle Nitro-Entwicklung braucht.
Häufig gestellte Fragen
1. Kann Nitro Express.js vollständig ersetzen?
Ja. Nitro handhabt Routing, Middleware und Bereitstellung besser. Migrieren Sie, indem Sie Express-Middleware zu Nitro-Plugins und Routen zu server/api/ verschieben.
2. Wie geht Nitro mit Datenbankverbindungen um?
Verwenden Sie Nitro-Plugins, um Pools beim Start zu initialisieren. Die Speicherschicht abstrahiert das Caching, aber für SQL bringen Sie Ihr eigenes ORM mit (Prisma, Drizzle).
3. Ist Nitro produktionsreif?
Absolut. Nuxt verwendet Nitro für Millionen von Produktionswebsites. Es ist für den Skalierungsbedarf kampferprobt.
4. Kann ich Nitro mit GraphQL verwenden?
Ja. Fügen Sie einen GraphQL-Handler in server/api/graphql.post.ts hinzu. Verwenden Sie jede beliebige Node GraphQL-Bibliothek – Nitro schränkt Sie nicht ein.
5. Was ist der Unterschied zwischen Nitro und Hono?
Hono ist ein leichter Router. Nitro ist ein vollständiges Server-Toolkit mit Builds, Presets und Speicher. Verwenden Sie Hono für Microservices, Nitro für vollständige Backends.
Fazit
NitroJs denkt die Backend-Entwicklung neu, indem es Ihre API in ein portables Artefakt kompiliert. Sie erhalten Dateisystem-Routing, TypeScript-Sicherheit und universelle Bereitstellung ohne Boilerplate. Erstellen Sie Ihre nächste REST-API mit Nitro und validieren Sie sie mit Apidog. Ihr zukünftiges Ich wird es Ihnen danken, wenn Sie mit einer einzigen Konfigurationszeile von Node auf den Edge migrieren.
