Skip to main content
Web DevelopmentTutorials

The Nuxt 3 Module System: Extending Your Framework

Build custom Nuxt modules to encapsulate functionality, share code between projects, and create powerful development tools.

Mbeah Essilfie

Mbeah Essilfie

May 20, 2026 at 06:04 AM

9 min read 957 views
The Nuxt 3 Module System: Extending Your Framework

What Are Nuxt Modules?

Modules are the extension system for Nuxt. They run at build time and can:

  • Add plugins, composables, and components
  • Modify the Nuxt configuration
  • Hook into the build process
  • Add server routes and middleware

Creating a Basic Module

// modules/analytics/index.ts
import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    name: 'my-analytics',
    configKey: 'analytics',
  },
  defaults: {
    trackingId: '',
    debug: false,
  },
  setup(options, nuxt) {
    if (!options.trackingId) {
      console.warn('[analytics] No tracking ID provided')
      return
    }

    const resolver = createResolver(import.meta.url)

    // Add a plugin that runs on client
    addPlugin({
      src: resolver.resolve('./runtime/plugin.client'),
      mode: 'client',
    })

    // Make config available at runtime
    nuxt.options.runtimeConfig.public.analytics = {
      trackingId: options.trackingId,
      debug: options.debug,
    }
  },
})

The runtime plugin:

// modules/analytics/runtime/plugin.client.ts
export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig().public.analytics

  // Initialize analytics SDK
  const analytics = initAnalytics(config.trackingId)

  // Track page views on route change
  const router = useRouter()
  router.afterEach((to) => {
    analytics.pageView(to.fullPath)
  })

  return {
    provide: { analytics },
  }
})

Adding Composables

// modules/analytics/index.ts (in setup)
import { addImports } from '@nuxt/kit'

addImports({
  name: 'useAnalytics',
  from: resolver.resolve('./runtime/composables/useAnalytics'),
})
// modules/analytics/runtime/composables/useAnalytics.ts
export function useAnalytics() {
  const { $analytics } = useNuxtApp()

  function trackEvent(name: string, properties?: Record<string, unknown>) {
    $analytics.track(name, properties)
  }

  return { trackEvent }
}
Once registered, useAnalytics() is auto-imported in every component — no explicit imports needed.

Adding Server Routes

// In module setup
import { addServerHandler } from '@nuxt/kit'

addServerHandler({
  route: '/api/_analytics/collect',
  handler: resolver.resolve('./runtime/server/api/collect.post'),
})

Using Your Module

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['./modules/analytics'],
  analytics: {
    trackingId: 'UA-XXXXX',
    debug: process.env.NODE_ENV === 'development',
  },
})

Module Best Practices

  1. Always provide defaults — Don't require configuration for basic usage
  2. Respect the user's config — Don't override, extend
  3. Add TypeScript types — Augment module declarations
  4. Document publicly — Even internal modules deserve a README
  5. Test in isolation — Modules should work independently

Modules are Nuxt's superpower. They turn complex setup into single-line configuration.

TypeScriptVueNuxt
Mbeah Essilfie

Written by Mbeah Essilfie

Fullstack Software Developer

Read next

The Complete Guide to Vue 3 Composables
12 min read

The Complete Guide to Vue 3 Composables

Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.

Mbeah EssilfieMbeah Essilfie
982