AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Nuxt is a full-stack Vue framework designed for universal deployment. This skill provides essential guidance on Nuxt 5, covering its directory structure, file-based routing, server-side rendering, and Nitro-based server engine. It includes best practices for data fetching, state management, and modular architecture, helping developers leverage features like auto-imports and hybrid rendering.
What it does
- Explains the Nuxt 5 directory structure and configuration conventions.
- Details file-based routing, including typed and case-sensitive routes.
- Provides guidance on data fetching using useFetch and $fetch.
- Covers server-side rendering, hybrid rendering, and Nitro server integration.
- Explains how to extend applications using Nuxt Layers and modules.
- Outlines lifecycle hooks for build-time and runtime customization.
When to use it
- When starting a new full-stack project with Vue and Nuxt.
- When migrating existing projects to Nuxt 5 and Nitro v3.
- When implementing server-side rendering or hybrid rendering strategies.
- When creating reusable application layers or custom Nuxt modules.
- When optimizing data fetching patterns and state management in SSR environments.
Advantages
- Provides standardized patterns for Nuxt 5 development.
- Simplifies complex concepts like Nitro server integration and lifecycle hooks.
- Offers clear guidance on project structure and file-based routing.
- Supports efficient code reuse through the Nuxt Layers system.
Usage examples
- “How do I structure my Nuxt 5 project directory?”
- The agent explains the default app/ directory structure for Vue code and the root-level placement for server/, public/, and nuxt.config.ts files.
- “Explain how to use layers to share components between projects.”
- The agent provides instructions on using the extends property in nuxt.config.ts to import layers from local directories, git repositories, or npm packages.
- “How do I hook into the page navigation lifecycle?”
- The agent shows how to use nuxtApp.hook('page:finish', ...) within a plugin to execute code after navigation completes.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/antfu/nuxt/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip nuxt.zip -d .agents/skills
Documentation by Anthony Fu
Nuxt is a full-stack Vue framework that provides server-side rendering, file-based routing, auto-imports, and a powerful module system. It uses Nitro as its server engine for universal deployment across Node.js, serverless, and edge platforms.
The skill is based on Nuxt 5.x (
5.0.0-0), generated at 2026-11-05.
Directory layout: the default
srcDirisapp/— Vue app code (app.vue,components/,composables/,pages/, etc.) lives underapp/, whileserver/,shared/,public/,modules/,layers/andnuxt.config.tsstay at the project root. The~/@aliases point atapp/; use~~/@@for the root.
Nuxt 5 note: Nuxt 5 makes many former experimental flags the default. The biggest shifts for agents: server code moves to Nitro v3 (h3 v2, Web-standard
Request/Response), server utilities import fromnuxt/serverand are no longer auto-imported by default,$fetch/useFetchare typed from generated route types, routing is case-sensitive and typed by default, and the bundler is Vite 8 (Rolldown). Nuxt 5 requires Node22.19/24.11+. A Nitro v2 compatibility layer (nitroLegacy) keeps older server code building during migration. See individual references for details.
Core
| Topic | Description | Reference |
|---|---|---|
| Directory Structure | Nuxt 4 app/ srcDir, shared/, aliases, conventions | core-directory-structure |
| Configuration | nuxt.config.ts, app.config.ts, aliases, Nuxt 5 defaults, jiti removal, experimental | core-config |
| CLI Commands | Dev server, build, generate, preview, and utility commands | core-cli |
| Routing | File-based routing, case-sensitive + typed routes, named views, layout props, middleware | core-routing |
| Data Fetching | useFetch, useAsyncData, $fetch, typed routes, createUseFetch factories, caching | core-data-fetching |
| Modules | Creating and using Nuxt modules, Nuxt Kit utilities | core-modules |
| Deployment | Platform-agnostic deployment with Nitro, Vercel, Netlify, Cloudflare | core-deployment |
Features
| Topic | Description | Reference |
|---|---|---|
| Composables Auto-imports | Vue/Nuxt composables, custom composables, shared/, useAnnouncer | features-composables |
| Components Auto-imports | Component naming, lazy loading, hydration strategies | features-components-autoimport |
| Built-in Components | NuxtLink, NuxtPage, NuxtLayout, NuxtAnnouncer, ClientOnly, and more | features-components |
| State Management | useState composable, SSR-friendly state, Pinia integration | features-state |
| Server Routes | API routes, nuxt/server imports, Nitro v3 (h3 v2), sessions, middleware | features-server |
Rendering
| Topic | Description | Reference |
|---|---|---|
| Rendering Modes | Universal (SSR), client-side (SPA), hybrid rendering, route rules | rendering-modes |
Best Practices
| Topic | Description | Reference |
|---|---|---|
| Data Fetching Patterns | Efficient fetching, caching, parallel requests, error handling | best-practices-data-fetching |
| SSR & Hydration | Avoiding context leaks, hydration mismatches, composable patterns | best-practices-ssr |
Advanced
| Topic | Description | Reference |
|---|---|---|
| Layers | Extending applications with reusable layers | advanced-layers |
| Lifecycle Hooks | Build-time, runtime, and server hooks | advanced-hooks |
| Module Authoring | Publishable modules with Nuxt Kit, keyed composables, dependencies | advanced-module-authoring |
Files
- ATTRIBUTION.mdAdded by AutoGineer889 B
- GENERATION.md134 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md4.5 KiB
- references/advanced-hooks.md7.2 KiB
- references/advanced-layers.md5.1 KiB
- references/advanced-module-authoring.md16.5 KiB
- references/best-practices-data-fetching.md9.2 KiB
- references/best-practices-ssr.md7.5 KiB
- references/core-cli.md4.8 KiB
- references/core-config.md10.5 KiB
- references/core-data-fetching.md11.4 KiB
- references/core-deployment.md5.1 KiB
- references/core-directory-structure.md9.8 KiB
- references/core-modules.md5.4 KiB
- references/core-routing.md6.8 KiB
- references/features-components-autoimport.md5.9 KiB
- references/features-components.md6.1 KiB
- references/features-composables.md7.2 KiB
- references/features-server.md11.1 KiB
- references/features-state.md3.9 KiB
- references/rendering-modes.md5.5 KiB
references/features-server.md
name: server-routes description: API routes, server middleware, and Nitro server engine in Nuxt
Server Routes
Nuxt includes the Nitro server engine for building full-stack applications with API routes and server middleware. Nuxt 5 runs on Nitro v3 (built on h3 v2 and srvx, using Web-standard Request/Response).
Nuxt 5: nuxt/server Imports (auto-imports off by default)
In Nuxt 5, Nitro's server helpers (defineEventHandler, getQuery, readBody, cookie/header helpers, createError, sendRedirect, getRouteRules, useRuntimeConfig, sessions…) are no longer auto-imported by default. Import them explicitly from nuxt/server — the runtime-agnostic surface that resolves to whatever server builder is configured and survives h3/Nitro majors:
// server/api/hello.ts
import { defineEventHandler, getQuery } from 'nuxt/server'
export default defineEventHandler((event) => {
const { name } = getQuery<{ name?: string }>(event)
return { message: `Hello, ${name ?? 'world'}!` }
})Your own exports from
server/utils/andshared/utils/are still auto-imported.Server code should import shared Nuxt composables from
#imports/server(not#imports).Re-enable Nitro auto-imports while migrating:
experimental.nitroAutoImports: true.defineEventHandlerpreserves your handler's return type — this is what types$fetch/useFetchcalls to the route. Annotate the returned value, not the handler.Helpers not in the
nuxt/serversurface (e.g.readMultipartFormData,lazyEventHandler,useKV,defineCachedHandler,defineTask) still come fromnitro/h3,nitro/kv,nitro/cache,nitro/task, etc.Also in
nuxt/server:getRequestHost/getRequestProtocol(pass{ xForwardedHost: true, xForwardedProto: true }only behind a trusted proxy),parseCookies,matchRouteRules(rules for another path),serverFetch(event, path)(in-process fetch of an app route; forwardscookie/authorization), anduseServerHooks()(renderer hooks likerender:html).toNuxtRequestEventwas removed.A handler file must default-export
defineEventHandlerfromnuxt/server(not h3's). It may return JSON-serializable data, aResponse, or aReadableStream. For a handler needing the runtime's own event (proxyRequest,event.waitUntil(), ...), importdefineEventHandlerfromnitro/h3instead (Nitro v3 only, register asnitro3).Only files directly in
server/utils/are auto-imported; re-export from a top-level file for subdirectory helpers.Don't import
nuxt/serverin Nuxt-process code (nuxt.config.ts, modulesetup, dev server handlers): runtime/app config come back empty. Readnuxt.optionsthere.
API Routes
Create files in server/api/ directory:
// server/api/hello.ts
import { defineEventHandler } from 'nuxt/server'
export default defineEventHandler((event) => {
return { message: 'Hello World' }
})Access at /api/hello. Return typing flows automatically to $fetch('/api/hello').
The examples below omit the
importlines for brevity; add them fromnuxt/server(or enablenitroAutoImports).
HTTP Methods
// server/api/users.get.ts - GET /api/users
export default defineEventHandler(() => {
return getUsers()
})
// server/api/users.post.ts - POST /api/users
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return createUser(body)
})
// server/api/users/[id].put.ts - PUT /api/users/:id
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
const body = await readBody(event)
return updateUser(id, body)
})
// server/api/users/[id].delete.ts - DELETE /api/users/:id
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
return deleteUser(id)
})Route Parameters
// server/api/posts/[id].ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
return getPost(id)
})
// Catch-all: server/api/[...path].ts
export default defineEventHandler((event) => {
const path = getRouterParam(event, 'path')
return { path }
})Query Parameters
// server/api/search.ts
// GET /api/search?q=nuxt&page=1
export default defineEventHandler((event) => {
const query = getQuery(event)
// { q: 'nuxt', page: '1' }
return search(query.q, Number(query.page))
})Request Body
// server/api/submit.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event)
// Validate and process body
return { success: true, data: body }
})Headers and Cookies
// server/api/auth.ts
import { defineEventHandler, getCookie, getRequestHeader, setCookie } from 'nuxt/server'
export default defineEventHandler((event) => {
// Read a request header
const auth = getRequestHeader(event, 'authorization')
// Read a cookie
const token = getCookie(event, 'token')
// Set a response header (Web Headers API)
event.res.headers.set('X-Custom-Header', 'value')
// Set a cookie
setCookie(event, 'token', 'new-token', {
httpOnly: true,
secure: true,
maxAge: 60 * 60 * 24, // 1 day
})
return { authenticated: !!token }
})Server Middleware
Runs on every request before routes:
// server/middleware/auth.ts
export default defineEventHandler((event) => {
const token = getCookie(event, 'token')
// Attach data to event context
event.context.user = token ? verifyToken(token) : null
})
// server/middleware/log.ts
export default defineEventHandler((event) => {
console.log(`${event.req.method} ${event.url.pathname}`)
})Access context in routes:
// server/api/profile.ts
export default defineEventHandler((event) => {
const user = event.context.user
if (!user) {
throw createError({ status: 401, message: 'Unauthorized' })
}
return user
})Error Handling
Nitro v3 / h3 v2 rename the error fields to Web-standard names: status/statusText (was statusCode/statusMessage):
// server/api/users/[id].ts
import { createError, defineEventHandler, getRouterParam } from 'nuxt/server'
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
const user = findUser(id)
if (!user) {
throw createError({
status: 404,
statusText: 'User not found',
})
}
return user
})Notes for Nitro v3:
The server error class is now
HTTPError(fromnitro/h3);createErrorfromnuxt/serverbuilds aNuxtError.NuxtErroris no longer a subclass ofHTTPError, so narrow withHTTPError.isError(error)orisNuxtError(error)rather thaninstanceof HTTPError.useRuntimeConfig()no longer accepts (or needs) theeventargument in server routes.The
H3Eventuses Web-standard APIs:event.url.pathname(notevent.path),event.req.method/event.req.headers(WebHeaders),event.res.status/event.res.headers.set(...)(notevent.node.res).
Request Validation
readValidatedBody / getValidatedQuery accept any Standard Schema (Zod, Valibot, ArkType). Validated shapes also type the matching $fetch/useFetch request:
// server/api/users.post.ts
import { defineEventHandler, readValidatedBody } from 'nuxt/server'
import { z } from 'zod'
export default defineEventHandler(async (event) => {
const user = await readValidatedBody(event, z.object({ name: z.string() }))
return { created: user.name }
})Invalid input is rejected with a 400 whose data.issues lists the failures.
Sessions
useSession (and getSession/updateSession/clearSession) come from nuxt/server and seal a sealed cookie session with iron-webcrypto, so they run under any server builder. No password is required — without one the session is sealed with a secret derived from appSecret (NUXT_APP_SECRET); pass a password of ≥32 chars to override. Default cookie name is nuxt-session.
// server/api/visits.ts
import { defineEventHandler, useSession } from 'nuxt/server'
export default defineEventHandler(async (event) => {
const session = await useSession<{ visits: number }>(event)
await session.update(data => ({ visits: (data.visits ?? 0) + 1 }))
return { visits: session.data.visits }
})h3 ships its own same-named session helpers (
import { useSession } from 'nitro/h3'); they are a separate, non-interchangeable implementation (cookie nameh3).
Server Utils
Auto-imported in server/utils/:
// server/utils/db.ts
export function useDb() {
return createDbConnection()
}// server/api/users.ts
export default defineEventHandler(() => {
const db = useDb() // Auto-imported
return db.query('SELECT * FROM users')
})Server Plugins
Run once when server starts. In Nitro v3 the factory is definePlugin from nitro:
// server/plugins/db.ts
import { definePlugin } from 'nitro'
export default definePlugin((nitroApp) => {
// Initialize database connection
const db = createDbConnection()
// Add to context
nitroApp.hooks.hook('request', (event) => {
event.context.db = db
})
})The
beforeResponse/afterResponsehooks are replaced by a singleresponsehook in Nitro v3.
Streaming Responses
// server/api/stream.ts
export default defineEventHandler((event) => {
event.res.headers.set('Content-Type', 'text/event-stream')
event.res.headers.set('Cache-Control', 'no-cache')
event.res.headers.set('Connection', 'keep-alive')
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
controller.enqueue(`data: ${JSON.stringify({ count: i })}\n\n`)
await new Promise(r => setTimeout(r, 1000))
}
controller.close()
},
})
return stream
})Nitro Builder
Nitro bundles the server with Rolldown by default. With the webpack/Rspack app builder, pick another via nitro.builder (or NITRO_BUILDER), e.g. builder: 'rspack', nitro: { builder: 'rspack' }. The Nitro rspack and bun builders are experimental; with experimental.nitroViteEnvironment, Vite builds the server and nitro.builder is ignored.
Server Storage
Key-value storage with multiple drivers. In Nitro v3 it is the KV layer: useKV comes from nitro/kv (was useStorage) and mounts are configured with nitro.kv (was nitro.storage):
// server/api/cache.ts
import { defineEventHandler } from 'nuxt/server'
import { useKV } from 'nitro/kv'
export default defineEventHandler(async (event) => {
const storage = useKV()
// Set value
await storage.setItem('key', { data: 'value' })
// Get value
const data = await storage.getItem('key')
return data
})Configure KV drivers in nuxt.config.ts:
export default defineNuxtConfig({
nitro: {
kv: {
redis: {
driver: 'redis',
url: 'redis://localhost:6379',
},
},
},
})<!-- Source references: - https://nuxt.com/docs/getting-started/server - https://nuxt.com/docs/directory-structure/server - https://nuxt.com/docs/guide/going-further/server-imports - https://nuxt.com/docs/getting-started/upgrade#migration-to-nitro-v3 - https://nuxt.com/docs/guide/modules/server-compatibility - https://nitro.build/blog/v3-beta -->
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
What our scanner noticed· Low risk
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Anthony Fu
- Publisher
- Anthony Fu (Community)
- Source
- antfu/skills · skills/nuxt · commit f63e9ec
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Anthony Fu.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download nuxt.zip