Building API Routes with Nuxt 3 Server Handlers

Nuxt 3's server directory turns your Nuxt project into a backend too. Here's how to structure server routes for forms, webhooks, and API proxies.

Richard GamoraRichard GamoraFullstack developer·4 min read
NuxtAPIServer

Nuxt 3's /server directory turns your project into a small backend in addition to a frontend. You can define API endpoints, middleware, and event handlers — all in TypeScript, all running on the same Nitro server that serves your pages.

Where the files go

Files in /server/api become routes under /api/*. /server/api/users.ts becomes /api/users. Use [param].ts for dynamic segments. Each handler exports a default eventHandler that receives the event and returns the response.

ts// server/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
})

Real cases this fits

  • Form submission endpoints for marketing pages (contact, newsletter signup) without a separate backend.
  • API proxies that hide secret keys — the client calls /api/openai and the server calls OpenAI with the key.
  • Webhooks for Stripe, GitHub, or anything that posts events into your app.
  • Lightweight CRUD for content tied to the site itself.

When to graduate to a separate backend

If your business logic outgrows simple endpoints — heavy database work, queues, multiple services, complex auth — a dedicated backend (Node, Laravel, whatever) makes sense. Nuxt's server is excellent for thin endpoints. For thick ones, it is the wrong tool.

About the author

Richard Gamora

Richard Gamora

Fullstack developer based in the Philippines, working mostly with Laravel and Vue.js, with eight years of production experience across web and mobile.

me@richardgamora.comUpwork ↗

More on Vue & Nuxt