Nuxt automatically reads the files in the plugins/ directory and loads them at the creation of the Vue application.
nuxt.config separately..server or .client suffix in the file name to load a plugin only on the server or client side.Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins.
-| plugins/
---| foo.ts // scanned
---| bar/
-----| baz.ts // not scanned
-----| foz.vue // not scanned
-----| index.ts // currently scanned but deprecated
Only foo.ts and bar/index.ts would be registered.
To add plugins in subdirectories, you can use the plugins option in nuxt.config.ts:
export default defineNuxtConfig({
plugins: [
'~/plugins/bar/baz',
'~/plugins/bar/foz',
],
})
The only argument passed to a plugin is nuxtApp.
export default defineNuxtPlugin((nuxtApp) => {
// Doing something with nuxtApp
})
It is also possible to define a plugin using an object syntax, for more advanced use cases. For example:
export default defineNuxtPlugin({
name: 'my-plugin',
enforce: 'pre', // or 'post'
async setup (nuxtApp) {
// this is the equivalent of a normal functional plugin
},
hooks: {
// You can directly register Nuxt app runtime hooks here
'app:created' () {
const nuxtApp = useNuxtApp()
// do something in the hook
},
},
env: {
// Set this value to `false` if you don't want the plugin to run when rendering server-only or island components.
islands: true,
},
})
enforce: import.meta.server ? 'pre' : 'post' would defeat any future optimization Nuxt is able to do for your plugins.
Nuxt does statically pre-load any hook listeners when using object-syntax, allowing you to define hooks without needing to worry about order of plugin registration.You can control the order in which plugins are registered by prefixing with 'alphabetical' numbering to the file names.
plugins/
| - 01.myPlugin.ts
| - 02.myOtherPlugin.ts
In this example, 02.myOtherPlugin.ts will be able to access anything that was injected by 01.myPlugin.ts.
This is useful in situations where you have a plugin that depends on another plugin.
10.myPlugin.ts would come before 2.myOtherPlugin.ts. This is why the example prefixes single digit numbers with 0.By default, Nuxt loads plugins sequentially. You can define a plugin as parallel so Nuxt won't wait until the end of the plugin's execution before loading the next plugin.
export default defineNuxtPlugin({
name: 'my-plugin',
parallel: true,
async setup (nuxtApp) {
// the next plugin will be executed immediately
},
})
If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the dependsOn array.
export default defineNuxtPlugin({
name: 'depends-on-my-plugin',
dependsOn: ['my-plugin'],
async setup (nuxtApp) {
// this plugin will wait for the end of `my-plugin`'s execution before it runs
},
})
You can use composables as well as utils within Nuxt plugins:
export default defineNuxtPlugin((nuxtApp) => {
const foo = useFoo()
})
However, keep in mind there are some limitations and differences:
nuxtApp instance.If you would like to provide a helper on the NuxtApp instance, return it from the plugin under a provide key.
export default defineNuxtPlugin(() => {
return {
provide: {
hello: (msg: string) => `Hello ${msg}!`,
},
}
})
export default defineNuxtPlugin({
name: 'hello',
setup () {
return {
provide: {
hello: (msg: string) => `Hello ${msg}!`,
},
}
},
})
You can then use the helper in your components:
<script setup lang="ts">
// alternatively, you can also use it here
const { $hello } = useNuxtApp()
</script>
<template>
<div>
{{ $hello('world') }}
</div>
</template>
composables instead of providing helpers to avoid polluting the global namespace and keep your main bundle entry small.ref or computed, it will not be unwrapped in a component <template>.If you return your helpers from the plugin, they will be typed automatically; you'll find them typed for the return of useNuxtApp() and within your templates.
useNuxtApp() to get the typed version. But in general, this should be avoided unless you are certain of the plugins' order.For advanced use-cases, you can declare the type of injected properties like this:
declare module '#app' {
interface NuxtApp {
$hello (msg: string): string
}
}
declare module 'vue' {
interface ComponentCustomProperties {
$hello (msg: string): string
}
}
export {}
If you want to use Vue plugins, like vue-gtag to add Google Analytics tags, you can use a Nuxt plugin to do so.
First, install the Vue plugin dependency:
npm install --save-dev vue-gtag-next
yarn add --dev vue-gtag-next
pnpm add -D vue-gtag-next
bun add -D vue-gtag-next
Then create a plugin file:
import VueGtag, { trackRouter } from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID',
},
})
trackRouter(useRouter())
})
Similarly, you can register a custom Vue directive in a plugin.
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('focus', {
mounted (el) {
el.focus()
},
getSSRProps (binding, vnode) {
// you can provide SSR-specific props here
return {}
},
})
})
~/plugins/my-directive.client.ts and provide a 'stub' directive for the server in ~/plugins/my-directive.server.ts.