Skip to main content

Server Routes

Decide when a Nuxt API route should call Convex and return a safe server response.

Do not wrap every Convex function in a Nuxt API route. Browser queries and mutations already call Convex with identity and type safety.

Use a Nitro route when

  • the operation requires a server-held third-party secret;
  • an external client calls your Nuxt API rather than Convex directly;
  • the route verifies a webhook;
  • Nuxt owns a response contract, cookie, or header;
  • the operation composes multiple server-only systems.

Validated route example

server/api/reports.post.ts
import { api } from '#convex/api'
import { serverConvex } from '#convex/server'
import { normalizeConvexError } from 'better-convex-nuxt/errors'
import { z } from 'zod'

const bodySchema = z.object({
  projectId: z.string().min(1),
})

export default defineEventHandler(async (event) => {
  const parsed = bodySchema.safeParse(await readBody(event))
  if (!parsed.success) {
    throw createError({ status: 400, statusText: 'Invalid request' })
  }

  try {
    return await serverConvex(event, { auth: 'required' }).action(api.reports.generate, {
      projectId: parsed.data.projectId,
    })
  } catch (error) {
    const callError = normalizeConvexError(error)
    const status = callError.kind === 'authentication' ? 401 : 502
    throw createError({ status, statusText: 'Report generation failed' })
  }
})

Validate at the HTTP boundary and again through Convex argument validators. The Convex function still enforces product authorization.

Return safe errors

Do not serialize raw upstream errors, request objects, credentials, or error.cause. Map expected domain errors to a public response contract and log only sanitized diagnostics.

Server middleware

Middleware can create a caller for request-scoped checks, but avoid turning every page request into an extra Convex call. Prefer route metadata and page queries when they already express the requirement.

Direct call or route

RequirementUse
Live page datauseConvexQuery
Interactive writeuseConvexMutation
Server-held secretNitro route
External webhookNitro route
Scheduled Convex workConvex scheduler/cron