Follow Best Practices

Build performant and maintainable Nuxt modules with these guidelines.

With great power comes great responsibility. While modules are powerful, here are some best practices to keep in mind while authoring modules to keep applications performant and developer experience great.

Handle Async Setup

As we've seen, Nuxt modules can be asynchronous. For example, you may want to develop a module that needs fetching some API or calling an async function.

However, be careful with asynchronous behaviors as Nuxt will wait for your module to setup before going to the next module and starting the development server, build process, etc. Prefer deferring time-consuming logic to Nuxt hooks.

If your module takes more than 1 second to setup, Nuxt will emit a warning about it.

Prefix Your Exports

Nuxt modules should provide an explicit prefix for any exposed configuration, plugin, API, composable, component, or server route to avoid conflicts with other modules, Nuxt internals, or user-defined code.

Ideally, prefix them with your module's name. For example, if your module is called nuxt-foo:

Type❌ Avoid✅ Prefer
Components<Button>, <Modal><FooButton>, <FooModal>
ComposablesuseData(), useModal()useFooData(), useFooModal()
Server routes/api/track, /api/data/api/_foo/track, /api/_foo/data

Server Routes

This is particularly important for server routes, where common paths like /api/auth, /api/login, or /api/user are very likely already used by the application.

Use a unique prefix based on your module name:

  • /api/_foo/... (using underscore prefix)
  • /_foo/... (for non-API routes)

Use Lifecycle Hooks

When your module needs to perform one-time setup tasks (like generating configuration files, setting up databases, or installing dependencies), use lifecycle hooks instead of running the logic in your main setup function.

import { addServerHandler, defineNuxtModule } from 'nuxt/kit'
import semver from 'semver'

export default defineNuxtModule({
  meta: {
    name: 'my-database-module',
    version: '1.0.0',
  },
  async onInstall (nuxt) {
    // One-time setup: create database schema, generate config files, etc.
    await generateDatabaseConfig(nuxt.options.rootDir)
  },
  async onUpgrade (options, nuxt, previousVersion) {
    // Handle version-specific migrations
    if (semver.lt(previousVersion, '1.0.0')) {
      await migrateLegacyData()
    }
  },
  setup (options, nuxt) {
    // Regular setup logic that runs on every build
    addServerHandler({ /* ... */ })
  },
})

This pattern prevents unnecessary work on every build and provides a better developer experience. See the lifecycle hooks documentation for more details.

Be TypeScript Friendly

Nuxt has first-class TypeScript integration for the best developer experience.

Exposing types and using TypeScript to develop modules benefits users even when not using TypeScript directly.

Use ESM Syntax

Nuxt relies on native ESM. Please read Native ES Modules for more information.

Document Your Module

Consider documenting module usage in the readme file:

  • Why use this module?
  • How to use this module?
  • What does this module do?

Linking to the integration website and documentation is always a good idea.

Provide a Demo

It's a good practice to make a minimal reproduction with your module and StackBlitz that you add to your module readme.

This not only provides potential users of your module a quick and easy way to experiment with the module but also an easy way for them to build minimal reproductions they can send you when they encounter issues.

Stay Version Agnostic

Nuxt, Nuxt Kit, and other new toolings are made to have both forward and backward compatibility in mind.

Please use "X for Nuxt" instead of "X for Nuxt 3" to avoid fragmentation in the ecosystem and prefer using meta.compatibility to set Nuxt version constraints.

Follow Starter Conventions

The module starter comes with a default set of tools and configurations (e.g. ESLint configuration). If you plan on open-sourcing your module, sticking with those defaults ensures your module shares a consistent coding style with other community modules out there, making it easier for others to contribute.