Builds applications with Nuxt 3 including pages, layouts, composables, server routes, and data fetching. Use when creating Vue applications with SSR, building full-stack Vue apps, or needing file-based routing with Vue.
Builds full-stack Vue applications with Nuxt 3 including pages, layouts, composables, and server routes. Use when creating Vue apps with SSR, file-based routing, or building full-stack applications with server-side APIs.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
The intuitive Vue framework for building full-stack web applications.
Create project:
npx nuxi@latest init my-app
cd my-app
npm install
npm run dev
my-app/
app.vue # Root component
nuxt.config.ts # Configuration
pages/ # File-based routing
components/ # Auto-imported components
composables/ # Auto-imported composables
layouts/ # Page layouts
server/ # Server routes & API
middleware/ # Route middleware
plugins/ # Vue plugins
public/ # Static assets
assets/ # Processed assets
<!-- pages/index.vue -->
<template>
<div>
<h1>Home Page</h1>
<NuxtLink to="/about">About</NuxtLink>
</div>
</template>
<!-- pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute();
const userId = route.params.id;
</script>
<template>
<div>User ID: {{ userId }}</div>
</template>
<!-- pages/[...slug].vue -->
<script setup lang="ts">
const route = useRoute();
// /a/b/c -> slug = ['a', 'b', 'c']
const segments = route.params.slug;
</script>
pages/
users/
[id]/
index.vue # /users/:id
profile.vue # /users/:id/profile
settings.vue # /users/:id/settings
<!-- layouts/default.vue -->
<template>
<div>
<AppHeader />
<main>
<slot />
</main>
<AppFooter />
</div>
</template>
<!-- layouts/admin.vue -->
<template>
<div class="admin-layout">
<AdminSidebar />
<div class="admin-content">
<slot />
</div>
</div>
</template>
<!-- pages/admin/dashboard.vue -->
<script setup lang="ts">
definePageMeta({
layout: 'admin',
});
</script>
<template>
<div>Admin Dashboard</div>
</template>
<script setup lang="ts">
// Automatic caching and deduplication
const { data, pending, error, refresh } = await useFetch('/api/users');
// With options
const { data: posts } = await useFetch('/api/posts', {
query: { limit: 10 },
pick: ['id', 'title'], // Only pick specific fields
transform: (data) => data.map(post => post.title),
});
</script>
<template>
<div v-if="pending">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<ul v-else>
<li v-for="user in data" :key="user.id">{{ user.name }}</li>
</ul>
</template>
<script setup lang="ts">
// For custom async operations
const { data, pending } = await useAsyncData('users', () => {
return $fetch('/api/users');
});
// With lazy loading
const { data: lazyData } = await useAsyncData(
'lazy-users',
() => $fetch('/api/users'),
{ lazy: true }
);
</script>
<script setup lang="ts">
// Direct fetch (no SSR hydration)
async function createUser(userData: User) {
const newUser = await $fetch('/api/users', {
method: 'POST',
body: userData,
});
return newUser;
}
</script>
<script setup lang="ts">
// Shared reactive state across components
const counter = useState('counter', () => 0);
function increment() {
counter.value++;
}
</script>
// composables/useCounter.ts
export function useCounter(initial = 0) {
const count = useState('counter', () => initial);
function increment() {
count.value++;
}
function decrement() {
count.value--;
}
return { count, increment, decrement };
}
<!-- Any component - auto-imported -->
<script setup lang="ts">
const { count, increment } = useCounter(10);
</script>
// server/api/users.get.ts
export default defineEventHandler(async (event) => {
const users = await prisma.user.findMany();
return users;
});
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const user = await prisma.user.create({ data: body });
return user;
});
// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id');
const user = await prisma.user.findUnique({ where: { id } });
if (!user) {
throw createError({
statusCode: 404,
message: 'User not found',
});
}
return user;
});
// server/api/search.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event);
// /api/search?q=test&limit=10
const { q, limit = 10 } = query;
return await search(q, Number(limit));
});
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession();
if (!loggedIn.value) {
return navigateTo('/login');
}
});
<!-- pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
});
</script>
// middleware/logger.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
console.log(`Navigating from ${from.path} to ${to.path}`);
});
// server/middleware/log.ts
export default defineEventHandler((event) => {
console.log('Request:', event.path);
});
<!-- components/AppHeader.vue -->
<template>
<header>
<NuxtLink to="/">Home</NuxtLink>
</header>
</template>
<!-- Automatically available in any page/component -->
<template>
<div>
<AppHeader />
</div>
</template>
components/
base/
Button.vue # <BaseButton />
Input.vue # <BaseInput />
user/
Avatar.vue # <UserAvatar />
<script setup lang="ts">
useHead({
title: 'My Page',
meta: [
{ name: 'description', content: 'Page description' },
{ property: 'og:title', content: 'My Page' },
],
link: [
{ rel: 'canonical', href: 'https://example.com/page' },
],
});
// Or use useSeoMeta
useSeoMeta({
title: 'My Page',
description: 'Page description',
ogTitle: 'My Page',
ogDescription: 'Page description',
ogImage: 'https://example.com/image.png',
});
</script>
// nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true },
modules: [
'@nuxt/ui',
'@pinia/nuxt',
'@nuxtjs/tailwindcss',
],
runtimeConfig: {
// Server-only
apiSecret: process.env.API_SECRET,
// Public (exposed to client)
public: {
apiBase: process.env.API_BASE || 'http://localhost:3000',
},
},
app: {
head: {
title: 'My App',
meta: [
{ name: 'description', content: 'My app description' },
],
},
},
routeRules: {
'/': { prerender: true },
'/api/**': { cors: true },
'/admin/**': { ssr: false },
},
});
// nuxt.config.ts
export default defineNuxtConfig({
// Global SSR setting
ssr: true,
// Per-route rules
routeRules: {
'/': { prerender: true }, // Static at build
'/blog/**': { isr: 3600 }, // ISR with 1hr revalidation
'/admin/**': { ssr: false }, // Client-only SPA
'/api/**': { cors: true }, // API routes
},
});
// plugins/my-plugin.ts
export default defineNuxtPlugin((nuxtApp) => {
return {
provide: {
hello: (name: string) => `Hello ${name}!`,
},
};
});
<script setup lang="ts">
const { $hello } = useNuxtApp();
const greeting = $hello('World'); // "Hello World!"
</script>
<!-- error.vue -->
<script setup lang="ts">
const props = defineProps<{
error: {
statusCode: number;
message: string;
};
}>();
const handleError = () => clearError({ redirect: '/' });
</script>
<template>
<div>
<h1>{{ error.statusCode }}</h1>
<p>{{ error.message }}</p>
<button @click="handleError">Go Home</button>
</div>
</template>
| Mistake | Fix |
|---|---|
| Calling composables outside setup | Only use in setup or other composables |
| Using reactive in server routes | Server routes are stateless |
| Missing await on useFetch | Always await data fetching |
| Not handling loading states | Check pending before data |
| Hardcoding env variables | Use runtimeConfig |
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.