Suggest an editImprove this articleRefine the answer for “What are plugins in Nuxt?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Nuxt plugins** are files in the `plugins/` directory that run once at app startup, registering Vue plugins or injecting global helpers. Use `vueApp.use()` for Vue integrations, `return { provide: { ... } }` to expose values via `useNuxtApp()`. Suffix `.client.ts` or `.server.ts` to control where they run. ```javascript export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(SomePlugin) return { provide: { helper: myHelper } } }) ``` **Key point:** plugins run once at startup, composables run per component.Shown above the full answer for quick recall.Answer (EN)Image**Nuxt plugins** are files in the `plugins/` directory that run once during app initialization, registering Vue plugins, utilities, or global helpers before any component mounts. ## Theory ### TL;DR - Think of plugins as airport ground crew: they set up services (auth, notifications, API clients) before the app starts, so every page has access without asking - Plugins run once at startup; composables run per component; middleware runs per route - Use a plugin when you need a Vue integration (`vueApp.use()`) or a global injectable (`provide`) - Suffix `.client.ts` for browser-only code, `.server.ts` for SSR-only code - Nuxt sorts plugins alphabetically; numeric prefixes (`01.auth.ts`) control order ### Quick example ```javascript // plugins/toast.client.ts - runs only in the browser import Toast from 'vue-toastification' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(Toast, { timeout: 3000 }) // Toast is now registered globally on the Vue app }) // In any component or page: const { $toast } = useNuxtApp() $toast.success('User saved!') ``` One registration, available everywhere. No imports in individual components. ### Key difference Plugins execute during Nuxt's startup phase, before hydration. The Vue app gets the plugin before any component tree is built. Composables, by contrast, run on demand inside component setup functions. Put per-component logic in a plugin and you bloat every page load. Call a composable at startup time like a plugin and you hit context errors. ### When to use - Vue plugin integration (`vue-toastification`, `pinia`, `i18n`) -> plugin with `vueApp.use()` - Global API client available everywhere -> plugin with `provide: { api }` - Reusable stateless logic -> composable - Route-specific logic -> middleware - Browser-only code (analytics, localStorage) -> `plugin.client.ts` - Server-only code (database connections) -> `plugin.server.ts` ### How Nuxt loads plugins Nuxt scans `plugins/` at build time and registers each file automatically. At startup, it executes them sequentially in alphabetical order. Client plugins run after hydration (post-mount), server plugins run per request inside the Nitro engine. The `provide` object from each plugin gets merged into `useNuxtApp()` context via Vue's `app.provide()`. That's why `$toast` or `$api` appears on `useNuxtApp()` without any explicit import in your component. Nuxt 3.10+ also supports `parallel: true` inside `defineNuxtPlugin` for plugins with no dependencies on each other. On large apps this cuts startup time noticeably. ### Common mistakes **1. Missing `.client.ts` suffix for browser-only code** ```javascript // Wrong: plugins/analytics.ts // Runs on SSR AND client = double tracking, crashes on window references // Fix: plugins/analytics.client.ts export default defineNuxtPlugin(() => { window.analytics.init() // window is safe here }) ``` **2. Wrong plugin order for dependencies** ```javascript // Wrong: plugins/api.ts loads before plugins/auth.ts // api.ts tries to read an auth token that doesn't exist yet // Fix: rename to 01.auth.ts and 02.api.ts // Nuxt sorts alphabetically, numeric prefixes win ``` This is the most common silent bug I see in Nuxt repos: auth and API loaded in the wrong order because no one added numeric prefixes until something broke in production. **3. Forgetting to return `provide`** ```javascript // Wrong: export default defineNuxtPlugin(() => { const api = { getUser: (id) => $fetch(`/api/users/${id}`) } // api is defined but never exposed to the app }) // Fix: export default defineNuxtPlugin(() => { const api = { getUser: (id) => $fetch(`/api/users/${id}`) } return { provide: { api } } }) // Now: const { $api } = useNuxtApp() works in any component ``` **4. Data fetching directly inside plugin initialization** Avoid fetch calls inside plugin setup code. They run outside the component lifecycle, so `useAsyncData` and `useFetch` are not available. Move data fetching to composables where they have access to the proper request context. ### Real-world usage - `vue-toastification` -> global toast notifications in e-commerce checkouts - `Pinia` -> store setup in SaaS dashboards (common in nuxtjs/starter repos) - `Supabase` -> auth client available app-wide in CMS and content sites - `Day.js` -> date formatting utility injected globally in blogging platforms - `Sentry` -> error tracking initialized once for the whole app ### Follow-up questions **Q:** How does Nuxt determine plugin execution order? **A:** Alphabetically by filename. Prefix with numbers to control it: `01.auth.ts` runs before `02.api.ts`. **Q:** What is the difference between `provide` and `vueApp.use()`? **A:** `vueApp.use()` registers a Vue plugin (directives, components, global install logic). `provide` injects a value into Nuxt's context, accessible via `useNuxtApp()`. You often use both in the same plugin. **Q:** Can a Nuxt plugin be async? **A:** Yes. Pass `async (nuxtApp) => { ... }` to `defineNuxtPlugin`. Nuxt awaits async plugins before rendering, so keep them fast or every request will wait on them. **Q:** How do plugins handle SSR hydration mismatches? **A:** Use `.client.ts` for plugins that touch browser APIs. For shared state between server and client, use `useState()` inside the plugin rather than a plain variable. **Q:** What is `parallel: true` and when do you use it? **A:** Added in Nuxt 3.10. Lets a plugin run in parallel with others instead of waiting for the previous one to finish. Use it for plugins with no dependencies on each other. Reduces startup time on apps with many plugins. ## Examples ### Registering a Vue plugin ```javascript // plugins/toast.client.ts import Toast from 'vue-toastification' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(Toast, { timeout: 3000 }) }) // pages/index.vue const { $toast } = useNuxtApp() async function saveUser(data) { await $fetch('/api/user', { method: 'POST', body: data }) $toast.success('Saved!') } ``` One import, one registration, available in every page and component. This covers the majority of plugin use cases. ### Global API client with provide ```javascript // plugins/supabase.ts import { createClient } from '@supabase/supabase-js' export default defineNuxtPlugin(() => { const config = useRuntimeConfig() const client = createClient( config.public.supabaseUrl, config.public.supabaseKey ) return { provide: { supabase: client } } }) // components/Login.vue const { $supabase } = useNuxtApp() async function login(email, password) { const { data, error } = await $supabase.auth.signInWithPassword({ email, password }) if (error) console.error(error.message) } ``` The Supabase client initializes once, reuses its connection pool, and is available everywhere without re-importing. Standard pattern in NuxtContent-based CMS starters.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.