--- trigger: glob glob: app/*.vue --- | No | Category | Guideline | Description | Do | Don't | Code Good | Code Bad | Severity | Docs URL | |----|----------|-----------|-------------|----|-------|-----------|----------|----------|----------| | 1 | Routing | Use file-based routing | Create routes by adding files in pages directory | pages/ directory with index.vue | Manual route configuration | pages/dashboard/index.vue | Custom router setup | Medium | https://nuxt.com/docs/getting-started/routing | | 2 | Routing | Use dynamic route parameters | Create dynamic routes with bracket syntax | [id].vue for dynamic params | Hardcoded routes for dynamic content | pages/posts/[id].vue | pages/posts/post1.vue | Medium | https://nuxt.com/docs/getting-started/routing | | 3 | Routing | Use catch-all routes | Handle multiple path segments with [...slug] | [...slug].vue for catch-all | Multiple nested dynamic routes | pages/[...slug].vue | pages/[a]/[b]/[c].vue | Low | https://nuxt.com/docs/getting-started/routing | | 4 | Routing | Define page metadata with definePageMeta | Set page-level configuration and middleware | definePageMeta for layout middleware title | Manual route meta configuration | definePageMeta({ layout: 'admin', middleware: 'auth' }) | router.beforeEach for page config | High | https://nuxt.com/docs/api/utils/define-page-meta | | 5 | Routing | Use validate for route params | Validate dynamic route parameters before rendering | validate function in definePageMeta | Manual validation in setup | definePageMeta({ validate: (route) => /^\d+$/.test(route.params.id) }) | if (!valid) navigateTo('/404') | Medium | https://nuxt.com/docs/api/utils/define-page-meta | | 6 | Rendering | Use SSR by default | Server-side rendering is enabled by default | Keep ssr: true (default) | Disable SSR unnecessarily | ssr: true (default) | ssr: false for all pages | High | https://nuxt.com/docs/guide/concepts/rendering | | 7 | Rendering | Use .client suffix for client-only components | Mark components to render only on client | ComponentName.client.vue suffix | v-if with process.client check | Comments.client.vue |
| Medium | https://nuxt.com/docs/guide/directory-structure/components | | 8 | Rendering | Use .server suffix for server-only components | Mark components to render only on server | ComponentName.server.vue suffix | Manual server check | HeavyMarkdown.server.vue | v-if="process.server" | Low | https://nuxt.com/docs/guide/directory-structure/components | | 9 | DataFetching | Use useFetch for simple data fetching | Wrapper around useAsyncData for URL fetching | useFetch for API calls | $fetch in onMounted | const { data } = await useFetch('/api/posts') | onMounted(async () => { data.value = await $fetch('/api/posts') }) | High | https://nuxt.com/docs/api/composables/use-fetch | | 10 | DataFetching | Use useAsyncData for complex fetching | Fine-grained control over async data | useAsyncData for CMS or custom fetching | useFetch for non-URL data sources | const { data } = await useAsyncData('posts', () => cms.getPosts()) | const { data } = await useFetch(() => cms.getPosts()) | Medium | https://nuxt.com/docs/api/composables/use-async-data | | 11 | DataFetching | Use $fetch for non-reactive requests | $fetch for event handlers and non-component code | $fetch in event handlers or server routes | useFetch in click handlers | async function submit() { await $fetch('/api/submit', { method: 'POST' }) } | async function submit() { await useFetch('/api/submit') } | High | https://nuxt.com/docs/api/utils/dollarfetch | | 12 | DataFetching | Use lazy option for non-blocking fetch | Defer data fetching for better initial load | lazy: true for below-fold content | Blocking fetch for non-critical data | useFetch('/api/comments', { lazy: true }) | await useFetch('/api/comments') for footer | Medium | https://nuxt.com/docs/api/composables/use-fetch | | 13 | DataFetching | Use server option to control fetch location | Choose where data is fetched | server: false for client-only data | Server fetch for user-specific client data | useFetch('/api/user-preferences', { server: false }) | useFetch for localStorage-dependent data | Medium | https://nuxt.com/docs/api/composables/use-fetch | | 14 | DataFetching | Use pick to reduce payload size | Select only needed fields from response | pick option for large responses | Fetching entire objects when few fields needed | useFetch('/api/user', { pick: ['id', 'name'] }) | useFetch('/api/user') then destructure | Low | https://nuxt.com/docs/api/composables/use-fetch | | 15 | DataFetching | Use transform for data manipulation | Transform data before storing in state | transform option for data shaping | Manual transformation after fetch | useFetch('/api/posts', { transform: (posts) => posts.map(p => p.title) }) | const titles = data.value.map(p => p.title) | Low | https://nuxt.com/docs/api/composables/use-fetch | | 16 | DataFetching | Handle loading and error states | Always handle pending and error states | Check status pending error refs | Ignoring loading states |
Loading...
| No loading indicator | High | https://nuxt.com/docs/getting-started/data-fetching | | 17 | Lifecycle | Avoid side effects in script setup root | Move side effects to lifecycle hooks | Side effects in onMounted | setInterval in root script setup | onMounted(() => { interval = setInterval(...) }) | | High | https://nuxt.com/docs/guide/concepts/nuxt-lifecycle | | 18 | Lifecycle | Use onMounted for DOM access | Access DOM only after component is mounted | onMounted for DOM manipulation | Direct DOM access in setup | onMounted(() => { document.getElementById('el') }) | | High | https://nuxt.com/docs/api/composables/on-mounted | | 19 | Lifecycle | Use nextTick for post-render access | Wait for DOM updates before accessing elements | await nextTick() after state changes | Immediate DOM access after state change | count.value++; await nextTick(); el.value.focus() | count.value++; el.value.focus() | Medium | https://nuxt.com/docs/api/utils/next-tick | | 20 | Lifecycle | Use onPrehydrate for pre-hydration logic | Run code before Nuxt hydrates the page | onPrehydrate for client setup | onMounted for hydration-critical code | onPrehydrate(() => { console.log(window) }) | onMounted for pre-hydration needs | Low | https://nuxt.com/docs/api/composables/on-prehydrate | | 21 | Server | Use server/api for API routes | Create API endpoints in server/api directory | server/api/users.ts for /api/users | Manual Express setup | server/api/hello.ts -> /api/hello | app.get('/api/hello') | High | https://nuxt.com/docs/guide/directory-structure/server | | 22 | Server | Use defineEventHandler for handlers | Define server route handlers | defineEventHandler for all handlers | export default function | export default defineEventHandler((event) => { return { hello: 'world' } }) | export default function(req, res) {} | High | https://nuxt.com/docs/guide/directory-structure/server | | 23 | Server | Use server/routes for non-api routes | Routes without /api prefix | server/routes for custom paths | server/api for non-api routes | server/routes/sitemap.xml.ts | server/api/sitemap.xml.ts | Medium | https://nuxt.com/docs/guide/directory-structure/server | | 24 | Server | Use getQuery and readBody for input | Access query params and request body | getQuery(event) readBody(event) | Direct event access | const { id } = getQuery(event) | event.node.req.query | Medium | https://nuxt.com/docs/guide/directory-structure/server | | 25 | Server | Validate server input | Always validate input in server handlers | Zod or similar for validation | Trust client input | const body = await readBody(event); schema.parse(body) | const body = await readBody(event) | High | https://nuxt.com/docs/guide/directory-structure/server | | 26 | State | Use useState for shared reactive state | SSR-friendly shared state across components | useState for cross-component state | ref for shared state | const count = useState('count', () => 0) | const count = ref(0) in composable | High | https://nuxt.com/docs/api/composables/use-state | | 27 | State | Use unique keys for useState | Prevent state conflicts with unique keys | Descriptive unique keys for each state | Generic or duplicate keys | useState('user-preferences', () => ({})) | useState('data') in multiple places | Medium | https://nuxt.com/docs/api/composables/use-state | | 28 | State | Use Pinia for complex state | Pinia for advanced state management | @pinia/nuxt for complex apps | Custom state management | useMainStore() with Pinia | Custom reactive store implementation | Medium | https://nuxt.com/docs/getting-started/state-management | | 29 | State | Use callOnce for one-time async operations | Ensure async operations run only once | callOnce for store initialization | Direct await in component | await callOnce(store.fetch) | await store.fetch() on every render | Medium | https://nuxt.com/docs/api/utils/call-once | | 30 | SEO | Use useSeoMeta for SEO tags | Type-safe SEO meta tag management | useSeoMeta for meta tags | useHead for simple meta | useSeoMeta({ title: 'Home', ogTitle: 'Home', description: '...' }) | useHead({ meta: [{ name: 'description', content: '...' }] }) | High | https://nuxt.com/docs/api/composables/use-seo-meta | | 31 | SEO | Use reactive values in useSeoMeta | Dynamic SEO tags with refs or getters | Computed getters for dynamic values | Static values for dynamic content | useSeoMeta({ title: () => post.value.title }) | useSeoMeta({ title: post.value.title }) | Medium | https://nuxt.com/docs/api/composables/use-seo-meta | | 32 | SEO | Use useHead for non-meta head elements | Scripts styles links in head | useHead for scripts and links | useSeoMeta for scripts | useHead({ script: [{ src: '/analytics.js' }] }) | useSeoMeta({ script: '...' }) | Medium | https://nuxt.com/docs/api/composables/use-head | | 33 | SEO | Include OpenGraph tags | Add OG tags for social sharing | ogTitle ogDescription ogImage | Missing social preview | useSeoMeta({ ogImage: '/og.png', twitterCard: 'summary_large_image' }) | No OG configuration | Medium | https://nuxt.com/docs/api/composables/use-seo-meta | | 34 | Middleware | Use defineNuxtRouteMiddleware | Define route middleware properly | defineNuxtRouteMiddleware wrapper | export default function | export default defineNuxtRouteMiddleware((to, from) => {}) | export default function(to, from) {} | High | https://nuxt.com/docs/guide/directory-structure/middleware | | 35 | Middleware | Use navigateTo for redirects | Redirect in middleware with navigateTo | return navigateTo('/login') | router.push in middleware | if (!auth) return navigateTo('/login') | if (!auth) router.push('/login') | High | https://nuxt.com/docs/api/utils/navigate-to | | 36 | Middleware | Reference middleware in definePageMeta | Apply middleware to specific pages | middleware array in definePageMeta | Global middleware for page-specific | definePageMeta({ middleware: ['auth'] }) | Global auth check for one page | Medium | https://nuxt.com/docs/guide/directory-structure/middleware | | 37 | Middleware | Use .global suffix for global middleware | Apply middleware to all routes | auth.global.ts for app-wide auth | Manual middleware on every page | middleware/auth.global.ts | middleware: ['auth'] on every page | Medium | https://nuxt.com/docs/guide/directory-structure/middleware | | 38 | ErrorHandling | Use createError for errors | Create errors with proper status codes | createError with statusCode | throw new Error | throw createError({ statusCode: 404, statusMessage: 'Not Found' }) | throw new Error('Not Found') | High | https://nuxt.com/docs/api/utils/create-error | | 39 | ErrorHandling | Use NuxtErrorBoundary for local errors | Handle errors within component subtree | NuxtErrorBoundary for component errors | Global error page for local errors |