install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/nuxt-server-routes" ~/.claude/skills/intense-visions-harness-engineering-nuxt-server-routes-853bf6 && rm -rf "$T"
manifest:
agents/skills/codex/nuxt-server-routes/SKILL.mdsource content
Nuxt Server Routes
Build fully-typed server API endpoints using Nitro's event-handler model and H3 utilities
When to Use
- You are creating REST API endpoints inside a Nuxt project under
orserver/api/server/routes/ - You need to read request bodies, query parameters, or headers server-side
- You want to return JSON, redirect, or stream responses from a Nuxt backend
- You are migrating Express/Fastify route logic into Nuxt's Nitro layer
- You need to understand how file-based routing maps to HTTP methods
Instructions
- Create files under
to expose routes atserver/api/
. Files under/api/<name>
map to the root path with noserver/routes/
prefix./api/ - Name files using the HTTP method suffix to restrict the method:
,users.get.ts
. Omit the suffix to handle all methods.users.post.ts - Export a default
function — this is the required Nitro entry point:defineEventHandler
// server/api/users.get.ts export default defineEventHandler(async (event) => { const users = await fetchUsersFromDb(); return users; // auto-serialized to JSON });
- Read query parameters with
, request body withgetQuery
, route params withreadBody
:getRouterParam
// server/api/users/[id].get.ts export default defineEventHandler(async (event) => { const id = getRouterParam(event, 'id'); const query = getQuery(event); // ?include=posts const user = await db.user.findUnique({ where: { id } }); if (!user) throw createError({ statusCode: 404, message: 'User not found' }); return user; });
- Throw errors with
— Nuxt serializes these into structured JSON error responses:createError
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' });
- Handle POST/PUT bodies with
— always validate the shape:readBody
// server/api/posts.post.ts export default defineEventHandler(async (event) => { const body = await readBody(event); if (!body.title) throw createError({ statusCode: 400, message: 'title required' }); return db.post.create({ data: body }); });
- Set response headers or status manually when needed:
setResponseStatus(event, 201); setHeader(event, 'X-Custom-Header', 'value');
- Return raw non-JSON responses by setting content-type explicitly:
setHeader(event, 'Content-Type', 'text/plain'); return 'Hello plain text';
- Use
for shared server-side helpers — these are auto-imported within theserver/utils/
tree.server/
Details
Nuxt's server layer is powered by Nitro, which itself uses H3 as its HTTP framework. H3 is a minimal, composable HTTP toolkit where every request is represented as an
H3Event. All H3 utility functions accept this event as their first argument.
File-based routing:
server/ api/ users.get.ts → GET /api/users users.post.ts → POST /api/users users/[id].get.ts → GET /api/users/:id auth/ login.post.ts → POST /api/auth/login routes/ feed.xml.get.ts → GET /feed.xml
Dynamic catch-all routes:
Use
[...slug].ts to match multiple path segments:
// server/api/[...slug].ts export default defineEventHandler((event) => { const slug = getRouterParams(event).slug; return { path: slug }; });
Middleware within server routes:
You can apply server-side logic before any handler using
server/middleware/. Files here run on every request automatically (no registration needed):
// server/middleware/auth.ts export default defineEventHandler((event) => { const token = getHeader(event, 'authorization'); if (!token) throw createError({ statusCode: 401 }); event.context.user = verifyToken(token); });
Streaming responses:
Nitro supports streaming via Web Streams API for large payloads or SSE:
export default defineEventHandler((event) => { setHeader(event, 'Content-Type', 'text/event-stream'); return sendStream(event, createReadableStream()); });
Type safety with
:$fetch
On the client side, use
$fetch or useFetch — Nuxt infers the return type from the server handler automatically in full-stack TypeScript mode.
When NOT to use:
- Heavy CPU tasks — Nitro runs in a single-threaded worker; offload to a queue or worker thread
- File system access in edge deployments —
andadapter-cloudflare
have no Node.jsadapter-vercel-edge
modulefs
Source
https://nuxt.com/docs/guide/directory-structure/server
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.