Nuxt 3 gives you file-based routing, auto-imports, server routes, and hybrid rendering out of the box. These recipes help you use AI tools to build on that foundation without fighting the framework’s conventions. Every prompt here produces code that respects Nuxt’s directory structure, leverages auto-imports, and handles SSR/CSR boundaries correctly.
Server route recipes that handle auth, validation, and database access
Composable patterns for data fetching with useFetch and useAsyncData
Middleware and plugin recipes for auth guards and global state
Deployment prompts for Vercel, Cloudflare, and Netlify edge
Scenario: You need a POST endpoint for creating blog posts with Zod validation, auth checking, and proper error responses.
Tip
Create a Nuxt server route at server/api/posts.post.ts. Use defineEventHandler with readValidatedBody and a Zod schema for validation. The schema should require title (string, 3-200 chars), content (string, min 10 chars), categoryId (UUID string), tags (array of strings, max 5), and publishedAt (optional ISO date string). Check the Authorization header for a Bearer token, verify it using verifyJWT() from server/utils/auth.ts. If invalid, throw createError({ statusCode: 401, message: 'Unauthorized' }). On valid request, insert into the database using Drizzle ORM, return the created post with 201 status. Handle duplicate title with a 409 Conflict response. Write a companion test using $fetch from @nuxt/test-utils that covers valid creation, validation errors, auth failure, and duplicate title.
Expected output: Server route file, Zod schema, and test file with 4 test cases.
Scenario: Your pages call useFetch directly with duplicated error handling. You need a composable that standardizes this.
Tip
Create composables/useApiData.ts that wraps Nuxt’s useFetch with consistent patterns. The composable should: (1) Accept a URL string and options object. (2) Automatically add the auth token from useState('auth-token') to the Authorization header. (3) Transform error responses into a typed ApiError object with statusCode, message, and optional field-level errors. (4) Provide refresh() that re-fetches, clear() that resets data, and retry() that retries after an error. (5) Handle SSR correctly: during server rendering, use the request event’s cookies for auth instead of useState. (6) Type the return as { data: Ref<T | null>, error: Ref<ApiError | null>, pending: Ref<boolean>, refresh, clear, retry }. Create typed wrappers: useApiGet<T>(url), useApiPost<T>(url, body), useApiPut<T>(url, body), useApiDelete(url). Test that the composable handles SSR payload deduplication and client-side reactivity.
Expected output: Composable file with typed wrappers, ApiError type, and tests.
Scenario: Protected pages need to check authentication and transparently refresh expired tokens without redirecting the user.
Tip
Create three pieces: (1) middleware/auth.ts — a named route middleware that checks for a valid auth token in useState('auth'). If missing, redirect to /login with a redirect query param preserving the original URL. If the token is expired (check exp claim), call the refresh endpoint before allowing navigation. If refresh fails, clear auth state and redirect to login. (2) middleware/guest.ts — for login/register pages, redirect to /dashboard if already authenticated. (3) plugins/auth.ts — a Nuxt plugin that runs on app init, checks for an existing refresh token in cookies, and silently restores the session. On the server side, read the cookie from the event; on the client side, read from document.cookie. (4) A useAuth() composable that exposes login(email, password), register(data), logout(), refreshToken(), and user computed ref. Protect pages by adding definePageMeta({ middleware: 'auth' }). Test the full flow: login sets tokens, middleware blocks unauthenticated access, token refresh happens transparently, logout clears everything.
Expected output: Two middleware files, one plugin, one composable, and integration tests.
Scenario: Every page needs consistent meta tags, structured data, and an auto-generated sitemap.
Tip
Create a local Nuxt module at modules/seo/index.ts using defineNuxtModule. The module should: (1) Auto-inject useHead defaults for every page: charset, viewport, default title template, and common meta tags (og:site_name, twitter:card). (2) Provide a useSeo(options) composable that sets title, description, og:image, canonical URL, and JSON-LD structured data for the current page. (3) Register a Nitro plugin that generates /sitemap.xml by scanning all pages in the pages directory and querying the database for dynamic routes. (4) Add a robots.txt server route that references the sitemap URL. (5) Configuration via nuxt.config with seo: { siteUrl, defaultImage, twitterHandle }. Test that meta tags render correctly in SSR output.
Expected output: Module directory with index.ts, composable, Nitro plugins for sitemap and robots, and tests.
Scenario: Your marketing pages should be static, your dashboard SSR, and your blog ISR with 1-hour revalidation.
Tip
Configure hybrid rendering in nuxt.config.ts using routeRules. Set: (1) '/' and '/about' and '/pricing' to { prerender: true } for static generation at build time. (2) '/blog/**' to { isr: 3600 } for incremental static regeneration every hour. (3) '/dashboard/**' to { ssr: true } for server-side rendering on every request. (4) '/api/**' to { cors: true, headers: { 'cache-control': 'no-store' } } for API routes. (5) '/assets/**' to { headers: { 'cache-control': 'public, max-age=31536000, immutable' } } for static assets. Create a composables/useRenderMode.ts that detects the current rendering mode for debugging. Add a page at /debug/render-info (development only) showing the current route’s rendering strategy.
Expected output: Updated nuxt.config.ts, render mode composable, and debug page.
Scenario: Your dashboard needs live updates for order status changes without WebSocket complexity.
Tip
Implement SSE in Nuxt. (1) Create server/api/events.get.ts that returns an SSE stream using setResponseHeader(event, 'content-type', 'text/event-stream') and setResponseHeader(event, 'cache-control', 'no-cache'). Use createEventStream(event) from h3. Subscribe to a Redis pub/sub channel for order updates and push each update as an SSE event with JSON data. Handle client disconnection by cleaning up the Redis subscription. (2) Create composables/useSSE.ts wrapping EventSource with auto-reconnect, typed message parsing, and cleanup on component unmount. (3) Create composables/useOrderUpdates.ts that uses useSSE, filters for the current user’s orders, and updates the Pinia store reactively. (4) Show a toast notification when an order status changes. Test the SSE endpoint responds with correct headers and streams events.
Expected output: SSE server route, two composables, Pinia integration, and tests.
Scenario: Three Nuxt apps share components, composables, and styles. You need a shared layer.
Tip
Create a Nuxt layer at layers/ui-kit/. (1) Set up layers/ui-kit/nuxt.config.ts with defineNuxtConfig and export components, composables, and Tailwind preset. (2) Add shared components in layers/ui-kit/components/: Button, Input, Select, Modal, Card, Badge, Avatar — each with TypeScript props, Tailwind styling, and variants (size: sm/md/lg, variant: primary/secondary/outline/ghost). (3) Add shared composables: useToast(), useConfirmDialog(), useBreakpoint(). (4) Add a Tailwind preset in layers/ui-kit/tailwind.preset.ts with design system colors, fonts, and spacing. (5) In the consuming app, extend with extends: ['./layers/ui-kit']. Verify auto-imports work for layer components and composables. Write a test confirming layer components render in a consuming page.
Expected output: Layer directory with config, 7 components, 3 composables, Tailwind preset, and integration test.
Scenario: Your Nuxt app needs type-safe database queries, migrations, and seeding.
Tip
Set up Drizzle ORM with PostgreSQL in Nuxt. (1) Create server/db/schema.ts with tables: users (id uuid, email unique, name, hashedPassword, role enum, createdAt), posts (id uuid, title, slug unique, content text, authorId references users, status enum draft/published/archived, publishedAt, createdAt), comments (id uuid, postId references posts, authorId references users, content text, createdAt). (2) Create server/db/index.ts initializing the drizzle client from environment variable. (3) Create server/db/queries/ with typed functions: getUserByEmail(email), getPostsWithAuthor(page, pageSize), createPost(data), getPostBySlug(slug) with author and comment count. (4) Create drizzle.config.ts for migrations. (5) Create a seed script at server/db/seed.ts with 10 users, 50 posts, and 200 comments using Faker. (6) Add server/utils/db.ts providing a cached database instance. Test queries against a test database.
Expected output: Schema file, query functions, config, seed script, and query tests.
Scenario: You want a blog powered by Markdown files with frontmatter, code highlighting, and table of contents.
Tip
Set up Nuxt Content v2 for a blog. (1) Install @nuxt/content and configure with Shiki code highlighting, heading anchors, and TOC generation. (2) Create content/blog/ with 3 sample posts using frontmatter: title, description, author, date, tags array, image, draft boolean. (3) Create pages/blog/index.vue listing published posts sorted by date descending with pagination (10 per page). Show title, excerpt, author, date, and tags. (4) Create pages/blog/[...slug].vue for individual posts with <ContentRenderer>, TOC sidebar, prev/next navigation, and reading time. (5) Create components/content/ProseCode.vue to customize code blocks with copy-to-clipboard. (6) Add RSS feed at /api/rss.xml querying all published posts. Test blog listing, post rendering, and RSS output.
Expected output: Nuxt Content config, sample posts, blog pages, custom prose component, RSS route, and tests.
Scenario: Deploy your Nuxt app to Cloudflare Workers with D1 database, KV caching, and R2 storage.
Tip
Configure Nuxt for Cloudflare Workers deployment. (1) Set nitro: { preset: 'cloudflare-pages' } in nuxt.config. (2) Create wrangler.toml with D1 database binding, KV namespace for sessions, and R2 bucket for uploads. (3) Create server/utils/cf.ts providing typed access to Cloudflare bindings via event.context.cloudflare.env. (4) Create a session middleware at server/middleware/session.ts reading/writing session data to KV with 24-hour TTL. (5) Create a file upload route at server/api/upload.post.ts storing files in R2 and returning a public URL. (6) Update database queries to use D1 instead of PostgreSQL. (7) Add wrangler.toml for local development with --local D1. Test locally with npx wrangler dev.
Expected output: Nitro config, wrangler.toml, binding utilities, session middleware, upload route, and D1 queries.
Scenario: Your Nuxt app has zero tests. You need coverage for components, server routes, and composables.
Tip
Set up testing using @nuxt/test-utils and Vitest. (1) Configure vitest.config.ts with @nuxt/test-utils/module. (2) Create test utilities in tests/utils/: renderPage(route) for Nuxt-aware page rendering, mockAuth(user?) for authenticated state, createTestDB() for in-memory SQLite with schema. (3) Write component tests for 3 components using mountSuspended. (4) Write server route tests using $fetch with setup({ server: true }) for 2 API endpoints. (5) Write composable tests that mount a test component consuming each composable. (6) Add npm run test:unit and npm run test:integration scripts. Configure coverage with minimum 70% for server routes.
Expected output: Vitest config, test utilities, component tests, server route tests, composable tests, and updated scripts.
Scenario: Your Nuxt app scores 60 on Lighthouse. Page transitions feel slow and the bundle is over 1 MB.
Tip
Audit and optimize this Nuxt app for performance. (1) Run npx nuxi analyze and identify chunks over 50KB. Check if they can be lazy-loaded or replaced with lighter alternatives. (2) Replace all <img> tags with <NuxtImg> from @nuxt/image for responsive images, lazy loading below the fold, and WebP/AVIF format negotiation. (3) Enable experimental.payloadExtraction for separate payload files. (4) Add vite.build.rollupOptions.output.manualChunks to split vendor code into logical chunks. (5) Implement <NuxtLoadingIndicator> with a custom color. (6) Add useHead with preload hints for critical CSS and fonts. (7) Enable routeRules caching for static pages. Report before/after Lighthouse scores. Target: performance 90+, bundle under 300KB initial.
Expected output: Updated nuxt.config, NuxtImg replacements, chunk splitting config, and performance comparison.