Nuxt 3 Core Knowledge
Full Reference: See advanced.md for WebSocket composable, Nitro WebSocket handlers, Socket.IO integration, plugin pattern, SSE, and room management patterns.
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: nuxt for comprehensive documentation.
Directory Structure
| Directory |
Purpose |
pages/ |
File-based routing |
components/ |
Auto-imported components |
composables/ |
Auto-imported composables |
server/ |
Server routes & middleware |
layouts/ |
Page layouts |
middleware/ |
Route middleware |
Page Component
<script setup lang="ts">
// Auto-imports work: ref, computed, useFetch, etc.
const { data, pending } = await useFetch('/api/users')
definePageMeta({
layout: 'admin',
middleware: 'auth'
})
</script>
<template>
<div v-if="pending">Loading...</div>
<div v-else>{{ data }}</div>
</template>
Data Fetching
| Composable |
Purpose |
useFetch |
SSR-friendly fetch with caching |
useAsyncData |
Custom async logic |
$fetch |
Direct fetch (no SSR handling) |
useLazyFetch |
Non-blocking fetch |
Server Routes
// server/api/users.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event)
return await db.users.findMany()
})
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return await db.users.create(body)
})
Key Features
- Auto-imports (components, composables, utils)
- Hybrid rendering (SSR, SSG, ISR, SPA)
- Nitro server engine
- Built-in state with
useState
When NOT to Use This Skill
This skill is for Nuxt 3 (Vue meta-framework). DO NOT use for:
- Vue without Nuxt: Use
frontend-vue skill instead
- Nuxt 2: Consult KB for migration to Nuxt 3
- Next.js (React meta-framework): Use
nextjs-app-router skill instead
- Remix (React meta-framework): Use
remix skill instead
- SvelteKit: Use
sveltekit skill instead
- Astro: Use
astro skill instead
- Vite-only setup: Use
frontend-vue with Vite configuration
Anti-Patterns
| Anti-Pattern |
Why It's Wrong |
Correct Approach |
| Using $fetch instead of useFetch |
No SSR handling, data not cached |
Use useFetch for SSR-friendly fetching |
| Fetching in onMounted |
Client-side only, no SSR |
Fetch in setup with useFetch/useAsyncData |
| Not using auto-imports |
Unnecessary boilerplate |
Rely on auto-imports for components/composables |
| Secrets in public runtimeConfig |
Exposed to client, security risk |
Use server-only runtimeConfig (not public) |
| Ignoring route rules |
Missed performance opportunities |
Set prerender, swr, or ssr rules per route |
| No error.vue |
Poor error UX |
Create error.vue for global error handling |
Quick Troubleshooting
| Issue |
Possible Cause |
Solution |
| "useFetch is not defined" |
Auto-imports not working |
Check .nuxt/tsconfig.json is generated, restart dev server |
| Data not available on SSR |
Using $fetch instead of useFetch |
Replace $fetch with useFetch |
| "useState is not defined" |
Auto-import issue |
Use useState composable (Nuxt 3), ensure .nuxt is built |
| API route 404 in production |
Route not generated |
Check server/api/ structure, rebuild |
| Hydration mismatch |
Server/client render differently |
Use , ensure consistent state |
| Components not auto-imported |
Not in components/ directory |
Move to components/ or configure in nuxt.config |
Production Readiness
Security Configuration
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
// Server-only (not exposed to client)
dbPassword: process.env.DB_PASSWORD,
// Exposed to client via useRuntimeConfig()
public: {
apiBase: process.env.API_BASE,
},
},
});
Error Handling
<!-- error.vue -->
<script setup lang="ts">
import type { NuxtError } from '#app';
const props = defineProps<{ error: NuxtError }>();
const handleError = () => clearError({ redirect: '/' });
</script>
<template>
<div class="error-page">
<h1>{{ error.statusCode }}</h1>
<p>{{ error.message }}</p>
<button @click="handleError">Go Home</button>
</div>
</template>
Performance
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/blog/**': { swr: 3600 }, // Stale-while-revalidate
'/admin/**': { ssr: false }, // Client-only
},
});
API Security
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
// Validate input
const body = await readValidatedBody(event, (body) => {
return z.object({
email: z.string().email(),
name: z.string().min(2),
}).parse(body);
});
// Auth check
const session = await requireAuth(event);
return await createUser(body);
});
Testing
import { mountSuspended } from '@nuxt/test-utils/runtime';
import IndexPage from '~/pages/index.vue';
describe('Index Page', () => {
it('renders correctly', async () => {
const component = await mountSuspended(IndexPage);
expect(component.text()).toContain('Welcome');
});
});
Monitoring Metrics
| Metric |
Target |
| Time to First Byte |
< 200ms |
| First Contentful Paint |
< 1.5s |
| Hydration time |
< 500ms |
| API response time |
< 100ms |
Checklist
Reference Documentation
- Directory Structure
- Data Fetching Patterns