Back to list
mgd34msu

nuxt

by mgd34msu

Plug in, Receive good vibes.

2🍴 0📅 Jan 25, 2026

SKILL.md


name: nuxt description: 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.

Nuxt 3

The intuitive Vue framework for building full-stack web applications.

Quick Start

Create project:

npx nuxi@latest init my-app
cd my-app
npm install
npm run dev

Project Structure

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 & Routing

Basic Pages

<!-- pages/index.vue -->
<template>
  <div>
    <h1>Home Page</h1>
    <NuxtLink to="/about">About</NuxtLink>
  </div>
</template>

Dynamic Routes

<!-- pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute();
const userId = route.params.id;
</script>

<template>
  <div>User ID: {{ userId }}</div>
</template>

Catch-All Routes

<!-- pages/[...slug].vue -->
<script setup lang="ts">
const route = useRoute();
// /a/b/c -> slug = ['a', 'b', 'c']
const segments = route.params.slug;
</script>

Nested Routes

pages/
  users/
    [id]/
      index.vue      # /users/:id
      profile.vue    # /users/:id/profile
      settings.vue   # /users/:id/settings

Layouts

Default Layout

<!-- layouts/default.vue -->
<template>
  <div>
    <AppHeader />
    <main>
      <slot />
    </main>
    <AppFooter />
  </div>
</template>

Custom Layout

<!-- 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>

Data Fetching

useFetch

<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>

useAsyncData

<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>

$fetch

<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>

State Management

useState

<script setup lang="ts">
// Shared reactive state across components
const counter = useState('counter', () => 0);

function increment() {
  counter.value++;
}
</script>

Composables

// 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 Routes

API Endpoints

// 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;
});

Dynamic Routes

// 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;
});

Query Parameters

// 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

Route Middleware

// 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>

Global Middleware

// middleware/logger.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  console.log(`Navigating from ${from.path} to ${to.path}`);
});

Server Middleware

// server/middleware/log.ts
export default defineEventHandler((event) => {
  console.log('Request:', event.path);
});

Components

Auto-imports

<!-- components/AppHeader.vue -->
<template>
  <header>
    <NuxtLink to="/">Home</NuxtLink>
  </header>
</template>

<!-- Automatically available in any page/component -->
<template>
  <div>
    <AppHeader />
  </div>
</template>

Nested Components

components/
  base/
    Button.vue    # <BaseButton />
    Input.vue     # <BaseInput />
  user/
    Avatar.vue    # <UserAvatar />

SEO & Meta

<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>

Configuration

// 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 },
  },
});

Rendering Modes

// 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

// 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 Handling

<!-- 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>

Best Practices

  1. Use composables - Extract reusable logic
  2. Leverage auto-imports - Components, composables, utils
  3. Use server routes - API endpoints in same project
  4. Configure rendering - SSR, SSG, ISR per route
  5. Use TypeScript - Full type safety

Common Mistakes

MistakeFix
Calling composables outside setupOnly use in setup or other composables
Using reactive in server routesServer routes are stateless
Missing await on useFetchAlways await data fetching
Not handling loading statesCheck pending before data
Hardcoding env variablesUse runtimeConfig

Reference Files

Score

Total Score

60/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon