mcpbeat Sign in

Nuxt Core Skill for Claude

Nuxt 5 core framework with project setup, routing, SEO, error handling, and Vite 8/Nitro v3 configuration. Use when creating Nuxt 5 apps, setting up routing, or migrating config.

4k tokens
context cost
the whole folder, loaded on every use
3
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
202
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/secondsky/claude-skills --skill nuxt-core

The instruction itself

35 sections, as written by the author

Nuxt 5 Core Fundamentals

Project setup, configuration, routing, SEO, and error handling for Nuxt 5 applications.

Quick Reference

Version Requirements

| Package | Minimum | Recommended |

|---------|---------|-------------|

| nuxt | 5.0.0 | 5.x |

| vue | 3.5.0 | 3.5.x |

| nitro | 3.0.0 | 3.x |

| vite | 8.0.0 | 8.x |

| typescript | 5.0.0 | 5.x |

Key Commands

bunx nuxi@latest init my-app
bun run dev
bun run build
bun run preview
bun run postinstall
bunx nuxi typecheck
bunx nuxi add page about
bunx nuxi add component MyButton
bunx nuxi add composable useAuth

Secure Installation

Scaffolding tools like bunx nuxi init download and execute remote code. Before running, follow supply chain security best practices:

  • Block post-install scriptsnpm config set ignore-scripts true (or Bun: disabled by default)
  • Cooldown period — Wait 7 days for new package versions to be vetted by the community
  • Audit before installing — Run socket package score npm <pkg> or use socket npm install <pkg> to check packages

Load the dependency-upgrade skill for full security configuration including Socket CLI integration, cooldown setup, lockfile validation, and CI enforcement.

Directory Structure (Nuxt v5)

my-nuxt-app/
├── app/                    # Default srcDir
│   ├── assets/             # Build-processed assets (CSS, images)
│   ├── components/         # Auto-imported Vue components
│   ├── composables/        # Auto-imported composables
│   ├── layouts/            # Layout components
│   ├── middleware/         # Route middleware
│   ├── pages/              # File-based routing
│   ├── plugins/            # Nuxt plugins
│   ├── utils/              # Auto-imported utility functions
│   ├── app.vue             # Main app component
│   ├── app.config.ts       # App-level runtime config
│   ├── error.vue           # Error page component
│   └── router.options.ts   # Router configuration
│
├── server/                 # Server-side code (Nitro v3)
│   ├── api/                # API endpoints
│   ├── middleware/         # Server middleware
│   ├── plugins/            # Nitro plugins
│   ├── routes/             # Server routes
│   └── utils/              # Server utilities
│
├── shared/                 # Shared code (app + server)
│   ├── utils/              # Auto-imported shared utils
│   └── types/              # Auto-imported shared types
│
├── public/                 # Static assets (served from root)
├── content/                # Nuxt Content files (if using)
├── layers/                 # Nuxt layers
├── modules/                # Local modules
├── .nuxt/                  # Generated files (git ignored)
├── .output/                # Build output (git ignored)
├── nuxt.config.ts          # Nuxt configuration
├── tsconfig.json           # TypeScript configuration
└── package.json            # Dependencies

What's New in Nuxt 5

| Area | Nuxt 4 | Nuxt 5 |

|------|--------|--------|

| Bundler | Vite 6 (esbuild + Rollup) | Vite 8 (Rolldown) |

| Server engine | Nitro v2 (h3 v1) | Nitro v3 (h3 v2, Web Standard APIs) |

| Vite config | Separate client/server configs | Vite Environment API |

| JS runtime | JSX plugin included by default | JSX plugin optional (on-demand) |

| Client-only placeholder | Empty <div> | HTML comment node |

| callHook | Always returns Promise | May return void (sync when possible) |

| clearNuxtState | Sets to undefined | Resets to initial default value |

| Page component names | Auto-generated | Normalized to match route names |

| experimental.externalVue | Available | Removed (always mocked) |

Configuration

Basic nuxt.config.ts

export default defineNuxtConfig({
  future: {
    compatibilityVersion: 5
  },

  devtools: { enabled: true },

  modules: [
    '@nuxt/ui',
    '@nuxt/content',
    '@nuxt/image'
  ],

  runtimeConfig: {
    apiSecret: process.env.API_SECRET,
    databaseUrl: process.env.DATABASE_URL,

    public: {
      apiBase: process.env.API_BASE || 'https://api.example.com',
      appName: 'My App'
    }
  },

  app: {
    head: {
      title: 'My Nuxt App',
      meta: [
        { charset: 'utf-8' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' }
      ]
    }
  },

  nitro: {
    preset: 'cloudflare_pages'
  },

  typescript: {
    strict: true,
    typeCheck: true
  }
})

Vite 8 / Rolldown Configuration

Nuxt 5 uses Vite 8 with Rolldown as the bundler. Use rolldownOptions instead of rollupOptions:

export default defineNuxtConfig({
  vite: {
    build: {
      rolldownOptions: {
        output: {
          manualChunks: {
            vendor: ['vue', 'vue-router']
          }
        }
      }
    },

    optimizeDeps: {
      include: []
    }
  }
})

Vite Environment API

Nuxt 5 uses the Vite Environment API for environment-specific config. Use configEnvironment and applyToEnvironment instead of separate client/server configs:

// Module/plugin authors - use Vite plugins instead of extendViteConfig
addVitePlugin(() => ({
  name: 'my-plugin',
  config(config) {
    // Global vite configuration
  },
  configEnvironment(name, config) {
    // Environment-specific config
    if (name === 'client') {
      config.optimizeDeps ||= {}
      config.optimizeDeps.include ||= []
      config.optimizeDeps.include.push('my-package')
    }
  },
  applyToEnvironment(environment) {
    return environment.name === 'client'
  },
}))

Optional JSX Support

@vitejs/plugin-vue-jsx is no longer installed by default. Install it only if needed:

bun add -D @vitejs/plugin-vue-jsx

Nuxt will auto-detect .jsx/.tsx files and prompt installation.

Runtime Config Usage

const config = useRuntimeConfig()
const apiBase = config.public.apiBase
const apiSecret = config.apiSecret

In server routes (v5 change): useRuntimeConfig() no longer accepts event:

// Nuxt 4
export default defineEventHandler((event) => {
  const config = useRuntimeConfig(event)
})

// Nuxt 5
export default defineEventHandler(() => {
  const config = useRuntimeConfig()
})

App Config vs Runtime Config

| Feature | App Config | Runtime Config |

|---------|------------|----------------|

| Location | app.config.ts | nuxt.config.ts |

| Hot reload | Yes | No |

| Secrets | No | Yes (server-only) |

| Use case | UI settings, themes | API keys, URLs |

Routing

File-Based Routing

app/pages/
├── index.vue              → /
├── about.vue              → /about
├── users/
│   ├── index.vue          → /users
│   └── [id].vue           → /users/:id
└── blog/
    ├── index.vue          → /blog
    ├── [slug].vue         → /blog/:slug
    └── [...slug].vue      → /blog/* (catch-all)

v5 Change: Page component names are now normalized to match their route names. This ensures consistent <KeepAlive> behavior.

Dynamic Routes

<!-- app/pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const userId = computed(() => route.params.id)
const { data: user } = await useFetch(`/api/users/${userId.value}`)
</script>

<template>
  <div>
    <h1>{{ user?.name }}</h1>
  </div>
</template>
<script setup>
const goToUser = (id: string) => {
  navigateTo(`/users/${id}`)
}
</script>

<template>
  <NuxtLink to="/about">About</NuxtLink>
  <NuxtLink :to="`/users/${user.id}`">View User</NuxtLink>
  <NuxtLink to="/dashboard" prefetch>Dashboard</NuxtLink>
</template>

Route Middleware

// app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const { isAuthenticated } = useAuth()

  if (!isAuthenticated.value) {
    return navigateTo('/login')
  }
})
<!-- app/pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({
  middleware: 'auth'
})
</script>

Global Middleware

// app/middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  if (import.meta.client) {
    window.gtag?.('event', 'page_view', {
      page_path: to.path
    })
  }
})

SEO & Meta Tags

<script setup lang="ts">
useSeoMeta({
  title: 'My Page Title',
  description: 'Page description for search engines',
  ogTitle: 'My Page Title',
  ogDescription: 'Page description',
  ogImage: 'https://example.com/og-image.jpg',
  ogUrl: 'https://example.com/my-page',
  twitterCard: 'summary_large_image'
})
</script>

Dynamic Meta Tags

<script setup lang="ts">
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)

useSeoMeta({
  title: () => post.value?.title,
  description: () => post.value?.excerpt,
  ogImage: () => post.value?.image
})
</script>

Error Handling

Error Page

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

Throwing Errors (App-side)

In the Vue part of your app (the app/ directory), createError continues to work:

throw createError({
  statusCode: 404,
  statusMessage: 'Page Not Found',
  fatal: true
})

Error Boundaries (Component-Level)

<template>
  <NuxtErrorBoundary @error="handleError">
    <template #error="{ error, clearError }">
      <div>
        <h2>Something went wrong</h2>
        <p>{{ error.message }}</p>
        <button @click="clearError">Try again</button>
      </div>
    </template>
    <MyComponent />
  </NuxtErrorBoundary>
</template>

clearNuxtState Resets to Defaults (v5 Change)

// Nuxt 4: clearNuxtState sets state to undefined
// Nuxt 5: clearNuxtState resets state to its initial value

const count = useState('counter', () => 42)
count.value = 100

clearNuxtState('counter')
// Nuxt 5: count.value is now 42 (the default), not undefined

Common Anti-Patterns

Using process.env Instead of Runtime Config

// WRONG
const apiUrl = process.env.API_URL

// CORRECT
const config = useRuntimeConfig()
const apiUrl = config.public.apiBase

Missing Middleware Return

// WRONG
export default defineNuxtRouteMiddleware((to) => {
  if (!isAuthenticated.value) {
    navigateTo('/login')  // Missing return!
  }
})

// CORRECT
export default defineNuxtRouteMiddleware((to) => {
  if (!isAuthenticated.value) {
    return navigateTo('/login')
  }
})

Non-Reactive Route Params

// WRONG
const userId = route.params.id

// CORRECT
const userId = computed(() => route.params.id)

Troubleshooting

Build Errors / Type Errors:

rm -rf .nuxt .output node_modules/.vite && bun install && bun run dev

Route Not Found:

  • Check file is in app/pages/
  • Verify file extension is .vue
  • Check for typos in dynamic params [id].vue

Vite Plugin Warnings:

  • Use configEnvironment + applyToEnvironment instead of server/client options
  • Deprecated extendViteConfig({ server }) will show warnings

JSX Not Working:

  • Install @vitejs/plugin-vue-jsx if using .jsx/.tsx files
  • nuxt-data: Composables, data fetching, state management
  • nuxt-server: Server routes, API patterns (Nitro v3)
  • nuxt-production: Performance, testing, deployment, migration

Templates Available

See templates/ directory for:

  • Production-ready nuxt.config.ts
  • app.vue with proper structure

Version: 5.0.0 | Last Updated: 2026-03-30 | License: MIT

Other skills for the same job

different authors, same section of the catalogue
Internal Comms
by anthropics
vendor ×13

A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).

6k tokens
Competitive Ads Extractor
by frostant
×10

Extracts and analyzes competitors' ads from ad libraries (Facebook, LinkedIn, etc.) to understand what messaging, problems, and creative approaches are working. Helps inspire and improve your own ad campaigns.

2k tokens
Lead Research Assistant
by frostant
×8

Identifies high-quality leads for your product or service by analyzing your business, searching for target companies, and providing actionable contact strategies. Perfect for sales, business development, and marketing professionals.

2k tokens
Developer Growth Analysis
by frostant
×6

Analyzes your recent Claude Code chat history to identify coding patterns, development gaps, and areas for improvement, curates relevant learning resources from HackerNews, and automatically sends a personalized growth report to your Slack DMs.

4k tokens
App Store Optimization
by alirezarezvani
×3

Complete App Store Optimization (ASO) toolkit for researching, optimizing, and tracking mobile app performance on Apple App Store and Google Play Store

55k tokens scripts
Deeptools
by christophacham
×3

NGS analysis toolkit. BAM to bigWig conversion, QC (correlation, PCA, fingerprints), heatmaps/profiles (TSS, peaks), for ChIP-seq, RNA-seq, ATAC-seq visualization.

21k tokens scripts
Pymatgen
by christophacham
×3

Materials science toolkit. Crystal structures (CIF, POSCAR), phase diagrams, band structure, DOS, Materials Project integration, format conversion, for computational materials science.

26k tokens scripts
Enhance Prompt
by google-labs-code
vendor ×2

Transforms vague UI ideas into polished, Stitch-optimized prompts. Enhances specificity, adds UI/UX keywords, injects design system context, and structures output for better generation results.

3k tokens

How to use it

Copy the folder

Take secondsky/claude-nuxt-core from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npm. Without those the skill loads but fails at the first command.