In Nuxt, prefixes and suffixes might seem like small details, but they play a pivotal role in shaping how components, plugins, and middleware are structured and used. These naming conventions bring clarity, control, and optimised performance to your application by influencing how and when specific parts of your code run. From controlling client-side and server-side behaviour to lazy loading and custom configurations, mastering prefixes and suffixes can make a significant difference in your project's functionality and performance. This guide will walk you through the essential prefixes and suffixes in Nuxt, explore what they do and the ways they can streamline your development process.
These small details can easily get overlooked in the documentation, so here’s a comprehensive overview of all the prefixes and suffixes in Nuxt.
The .global.ts
suffix is used for defining global route middleware in Nuxt. Middleware is an essential concept in Nuxt that allows you to run specific logic before rendering a page or route. A .global.ts
file typically contains global middleware that executes before every route change, allowing you to set up things like authentication checks, global error handling, or logging.
auth.global.ts
could be a global middleware to check for user authentication before any route is accessed.export default defineNuxtRouteMiddleware((to, from) => {
const user = useAuth()
if (!user.isAuthenticated && to.name !== 'login') {
return navigateTo('/login')
}
})
The .server.vue
suffix indicates Vue components that will be rendered on the server side only. This is part of Nuxt’s hybrid rendering model, where certain components can be server-rendered to improve performance, especially for SEO-sensitive content. These components are not shipped to the client, meaning they are used only for server-side rendering (SSR) purposes.
<!-- components/HighlightedMarkdown.server.vue -->
<template>
<div v-html="renderedMarkdown"></div>
</template>
<script setup>
import MarkdownIt from 'markdown-it'
const props = defineProps({
content: {
type: String,
required: true,
},
})
const md = new MarkdownIt()
const renderedMarkdown = md.render(props.content)
</script>
Conversely, the .client.vue
suffix denotes that a component should be rendered only on the client side. This is useful when you have dynamic components that rely heavily on client-side JavaScript (such as components with complex interactions like maps or charts) and don’t need server-side rendering.
<template>
<div>
<!-- Only rendered on the client-side -->
<MapComponent />
</div>
</template>
In addition to controlling whether components render on the client or server, Nuxt allows components to be registered globally, making them accessible throughout the application. This global registration is particularly useful when you want components to be available in multiple places, such as within markdown files or across various views, without needing to import them each time.
There are two main methods for globally registering Vue components in Nuxt. First, you can place your component files inside the ~/components/global
directory, which Nuxt automatically scans and registers. Alternatively, you can add the .global.vue
suffix to your component file name, enabling Nuxt to treat it as a globally accessible component. These approaches simplify component management and streamline your code, especially when working with reusable components across your project.
The .server.ts
suffix refers to server-side-only plugins in Nuxt. Plugins in Nuxt can inject additional functionality into your application (such as external libraries, API calls, etc.). When you define a plugin with .server.ts
, it will only run during server-side rendering, making it useful for logic that needs to stay on the server (like sensitive API calls or fetching data during SSR).
export default defineNuxtPlugin(() => {
// Server-only logic here
return {
provide: {
fetchData: async () => { /* fetch data server-side */ }
}
}
})
The .client.ts
suffix is for client-side plugins, which are loaded only on the client. This is useful for logic or libraries that require access to the browser’s APIs (such as local storage, window, or document objects), which are unavailable on the server.
// plugins/vue-gtag.client.ts
import VueGtag, { trackRouter } from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID'
}
})
trackRouter(useRouter())
})
Although Nuxt doesn’t enforce this, it’s considered good practice to suffix API endpoint files with the corresponding HTTP method. For instance, naming a file users.get.ts
or user.post.ts
clearly indicates the file’s purpose and HTTP method, improving readability and organisation across your codebase.
It also minimises potential confusion when working with endpoints that might perform similar functions but require different HTTP methods, such as GET
, POST
, PUT
, or DELETE
.
// server/api/test.get.ts
export default defineEventHandler(() => 'Test get handler')
// server/api/test.post.ts
export default defineEventHandler(() => 'Test post handler')
Adopting this convention can make your codebase cleaner, easier to navigate, and more manageable, especially as your API grows in complexity.
In Nuxt, the Lazy
prefix is used to defer the loading of certain components or resources. Lazy loading improves the performance of an application by only loading components when they are required, such as when they are visible on the screen. This is especially useful for reducing initial load times on larger applications.
<!-- pages/index.vue -->
<script setup lang="ts">
const show = ref(false)
</script>
<template>
<div>
<h1>Mountains</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Show List</button>
</div>
</template>
auto-import
functionality, Nuxt automatically manages lazy loading with the Lazy
prefix, making it easier to handle large projects.When adding extra directories or subdirectories of components for auto-import scanning, we can customise the configuration further. For example, we can include a prefix
key to define a prefix for the components.
By default, component names incorporate their file path for usage. For instance, a component located at components/event/Update.vue
is used as <EventUpdate />
. Nuxt offers a configuration option, pathPrefix
, which accepts a boolean value to disable this default behaviour.
export default defineNuxtConfig({
components: [
// ~/components/admin-components/Btn.vue => <AdminBtn />
{ path: '~/components/admin-components', prefix: 'Special' },
// ~/calendar-module/components/event/Update.vue => <EventUpdate />
{ path: '~/calendar-module/components' },
// ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog />
{ path: '~/user-module/components', pathPrefix: false },
]
})
While discussing Lazy
, it’s worth noting that Nuxt has a few additional "lazy" features. Though they aren’t technically suffixes or prefixes, they’re still valuable to mention.
When using useFetch
, Nuxt waits for the asynchronous function to resolve before navigating to a new page. To prevent this on the client side, you can set lazy: true
.
Example:
<script setup lang="ts">
const { status, data: posts } = useFetch('/api/posts', {
lazy: true
})
</script>
This behaviour applies to useAsyncData
as well. Alternatively, Nuxt offers useLazyFetch
and useLazyAsyncData
as convenient shortcuts to achieve the same effect.
Example:
<script setup lang="ts">
const { status, data: posts } = useLazyFetch('/api/posts')
</script>
The lazy
prop in the NuxtIsland
component enables lazy loading for sections of your page where the NuxtIsland component is used. When lazy
is set to true
, the component delays its loading until it comes into view or when other user-defined conditions are met.
The loading
attribute is a native HTML property that guides the browser on how to load an image. By setting loading="lazy"
, the image's loading is deferred until it appears within the viewport.
Example:
<NuxtImg src="/nuxt-icon.png" loading="lazy" />
By understanding and effectively using prefixes and suffixes in Nuxt, you can take greater control over how components and plugins are handled in your application. Whether optimising loading times with lazy prefixes or defining server-side and client-specific logic, these conventions empower developers to build more efficient and organised code. With a few thoughtful configurations, you’ll make your Nuxt applications not only more performant but also easier to maintain and expand. So, as you continue developing with Nuxt, keep these powerful conventions in mind to maximise both productivity and performance.