Nitro is the server engine behind Nuxt, but it works standalone too. It's a universal JavaScript server that deploys anywhere — Node.js, Deno, Bun, Cloudflare Workers, AWS Lambda, and more.
Quick Start
npx giget nitro my-app
cd my-app && npm install && npm run dev
API Routes
Create routes by adding files to routes/:
// routes/api/users.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event)
return db.user.findMany({ take: Number(query.limit) || 10 })
})
// routes/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return db.user.create({ data: body })
})
// routes/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, "id")
const user = await db.user.findUnique({ where: { id } })
if (!user) throw createError({ statusCode: 404 })
return user
})
// routes/api/users/[id].patch.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, "id")
const body = await readBody(event)
return db.user.update({ where: { id }, data: body })
})
Built-in Caching
// routes/api/stats.get.ts
export default defineCachedEventHandler(async () => {
const stats = await computeExpensiveStats()
return stats
}, {
maxAge: 60 * 60, // 1 hour
swr: true, // Stale-while-revalidate
staleMaxAge: 3600 // Serve stale for 1h while revalidating
})
// Cached utility functions
const getConfig = defineCachedFunction(async (key: string) => {
return db.config.findUnique({ where: { key } })
}, {
maxAge: 300,
getKey: (key) => `config:${key}`
})
Middleware
// middleware/auth.ts
export default defineEventHandler(async (event) => {
const token = getHeader(event, "authorization")?.replace("Bearer ", "")
if (event.path.startsWith("/api/protected") && !token) {
throw createError({ statusCode: 401, message: "Unauthorized" })
}
if (token) {
event.context.user = await verifyToken(token)
}
})
// middleware/cors.ts
export default defineEventHandler((event) => {
setResponseHeaders(event, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"
})
})
Storage API — Universal Key-Value
// nitro.config.ts
export default defineNitroConfig({
storage: {
redis: { driver: "redis", url: "redis://localhost:6379" },
fs: { driver: "fs", base: "./data" },
db: { driver: "cloudflare-kv-binding", binding: "MY_KV" }
}
})
// routes/api/cache.ts
export default defineEventHandler(async (event) => {
const storage = useStorage("redis")
// Set
await storage.setItem("user:1", { name: "Alice" })
// Get
const user = await storage.getItem("user:1")
// List keys
const keys = await storage.getKeys("user:")
return { user, keys }
})
WebSocket
// routes/_ws.ts
export default defineWebSocketHandler({
open(peer) {
peer.subscribe("broadcast")
peer.send(JSON.stringify({ type: "connected", id: peer.id }))
},
message(peer, message) {
const data = JSON.parse(message.text())
peer.publish("broadcast", JSON.stringify({
from: peer.id,
...data
}))
},
close(peer) {
peer.publish("broadcast", JSON.stringify({
type: "disconnected", id: peer.id
}))
}
})
Deploy Anywhere
# Node.js
npx nitropack build --preset node-server
# Cloudflare Workers
npx nitropack build --preset cloudflare-module
# Vercel
npx nitropack build --preset vercel-edge
# AWS Lambda
npx nitropack build --preset aws-lambda
# Deno Deploy
npx nitropack build --preset deno-deploy
Key Takeaways
- Universal — same code runs on Node, Deno, Bun, Edge, Lambda
- File-based routing with HTTP method suffixes
- Built-in caching with SWR support
- Storage API for Redis, FS, KV with one interface
- WebSocket support
- Auto-imports for all utilities
Explore Nitro docs for the complete reference.
Building web scrapers or data pipelines? Check out my Apify actors for ready-made solutions, or email spinov001@gmail.com for custom development.
Top comments (0)