$ ls index/

engineering / frontend / nuxt

Nuxt: Composables vs Plugins

$cat engineering/frontend/nuxt/composables-vs-plugins.md

The Core Difference

Composables are on-demand tools — they do nothing until called from a component or another composable. Their lifecycle is tied to the caller: a watcher inside a composable is disposed when its component unmounts.

Plugins run automatically once per page load when the Nuxt app initializes. They run outside any component lifecycle, so watchers persist for the entire user session across all page navigations.

ComposablePlugin
When it runsWhen you call itApp startup, automatically
LifecycleComponent-scopedSession-scoped
Locationcomposables/plugins/
RegistrationCall in <script setup>Auto-registered by Nuxt

When to Use a Plugin

Use a plugin for logic that is:

  • Global — affects the whole app, not one component
  • Automatic — should activate on app start without being explicitly called
  • Persistent — needs to stay alive across all page navigations

Example: Language syncing tied to auth state

Goal: "When the app loads, and any time auth state changes, check the user's preferred language and apply it globally."

// plugins/language-sync.client.ts
export default defineNuxtPlugin(() => {
  const user = useSupabaseUser()

  watch(user, (newUser) => {
    if (newUser?.user_metadata?.language) {
      // apply language globally
    }
  }, { immediate: true })
})

If this were a composable, you'd still need to call useLanguageSync() somewhere — and calling it in app.vue is just doing manually what a plugin does automatically and more cleanly.

The app.vue Trap

A common mistake: putting app-wide logic in a composable, then calling it in app.vue to make it "global." This works, but app.vue becomes load-bearing infrastructure instead of layout. If the concern is truly app-wide and automatic, it belongs in plugins/.

Let's build something impactful together.

ertughaskan@gmail.com Find me online
Availability
WorkAvailable
RelocationOpen
FreelanceClosed
© 2026 Ertugrul Alex Haskan /cookiesVancouver, BC 🇨🇦

This site uses one optional Google Analytics cookie to see which pages get read. Nothing is set until you choose — cookie details.