Getting Started with Nuxt Modules

This guide aims to provide detailed insights and clear explanations to fully grasp the power and utility of Nuxt modules.

Mostafa Said
Nuxt 3

Mastering Nuxt 3 course is here!

Get notified when we release new tutorials, lessons, and other expert Nuxt content.

Click here to view the Nuxt 3 course

Nuxt.js is a powerful framework built on Vue.js, designed to create universal, server-side rendered (SSR) applications. One of its standout features is its modular architecture, which makes it incredibly flexible and extendable. In this article, we will dive deep into Nuxt modules, exploring what they are, why they are beneficial, and how to get started with creating and using them.

What are Nuxt Modules?

Nuxt modules are essentially packages that extend your Nuxt application's core functionality. They can modify the Nuxt configuration, register hooks, add plugins, and seamlessly integrate third-party libraries. By encapsulating functionality into modules, you can keep your codebase clean, organized, and maintainable.

If you want to learn everything about Nuxt Modules, checkout our comprehensive course “Nuxt Modules: The Ultimate Guide” on Vue School.

Types of Nuxt Modules

There are many types for Nuxt Modules. Each type has its own characteristics and place in the ecosystem.

Official Modules

Official modules are developed and maintained by the Nuxt team. These modules adhere to Nuxt’s best practices, ensuring compatibility and stability. They are prefixed with @nuxt/. Examples include @nuxt/image for optimizing images, @nuxt/content for content management, and @nuxt/ui for building beautiful and accessible user interfaces.

Community Modules

Community modules are developed by the Nuxt community. These modules can be used to fill gaps not covered by official modules. They cover a wide range of use cases, from SEO enhancements to integration with various APIs and services. They are prefixed with @nuxtjs/ . Examples include @nuxtjs/i18n for internationalization for Nuxt apps and @nuxtjs/google-fonts for easy access to Google Fonts.

Third-Party Modules

Third-party modules are developed by independent developers or companies. These modules may not always follow Nuxt conventions, but they can still be useful for integrating specific libraries or services that you might need.

Private/Local Modules

Private or local modules are custom modules specific to your application, developed internally to encapsulate and reuse functionality across different parts of your application. These are not shared with the community but are crucial for maintaining a clean and organized codebase within your project.

Why Use Nuxt Modules?

Nuxt Modules are important for many reasons. Let’s go through some of the main ones.

Reusability and Modularity

Modules allow you to encapsulate functionality in a reusable way. This modularity helps in keeping your codebase clean and organized. You can easily share modules between projects or with the community. For example, if you develop a custom authentication mechanism, encapsulating it in a module allows you to reuse it across multiple projects without duplicating code.

Simplified Configuration

Modules can abstract complex configurations, making it easier to integrate various functionalities without dealing with intricate details. For example, the @nuxtjs/tailwindcss module provides an easy way to integrate TailwindCSS with Nuxt.

Extensibility

Nuxt Lifecycle Hooks Example

Modules can hook into the Nuxt lifecycle and extend or modify the core functionality. This makes it possible to add custom behavior or integrate third-party services seamlessly. For instance, you might use a module to add custom middleware that runs during the build process, or to extend the server-side functionality with custom routes.

Community Support

Using well-maintained community modules ensures you have access to a wide range of functionalities without reinventing the wheel. The community actively contributes and maintains these modules, ensuring they stay up-to-date with the latest Nuxt releases. Additionally, community modules often come with extensive documentation and examples, making it easier to integrate them into your projects.

Creating Your First Nuxt Module

Let’s get hands-on and create a Nuxt module from scratch. We’ll start with a simple local module and then explore how to publish it for reuse in other projects.

Setting Up the Project

First, let’s create a new Nuxt project. Open your terminal and run the following commands:

mkdir nuxt-modules
cd nuxt-modules
npx nuxi@latest init nuxt-app
cd nuxt-app

This will scaffold a new Nuxt project with the necessary files and directories. Open the project in your favorite code editor to begin.

Creating a Local Module

We’ll start by creating a local module inside our project. Local modules reside within the project’s file structure and are specific to that project.

  1. Create a modules directory in the project root:
    mkdir modules
    
  2. Inside the modules directory, create a file named first-module.js with the below code:
    // modules/first-module.ts
    export default function () {
        console.log('Hello from the module!')
    }
    
  3. Run the development server to see your module in action:
    npm run dev
    

You should see the message "Hello from the module!" in your terminal. This confirms that your module is being loaded and executed during the build process.

We can also define a module using the defineNuxtModule function from @nuxt/kit:

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule((options, nuxt) => {

  console.log('Hello from the module!')
  
})

The defineNuxtModule function also allow us to use the object syntax to define our module:

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    // Usually the npm package name of your module
    name: '@nuxtjs/example',
    // The key in `nuxt.config` that holds your module options
    configKey: 'sample',
    // Compatibility constraints
    compatibility: {
      // Semver version of supported nuxt versions
      nuxt: '>=3.0.0'
    }
  },
  // Default configuration options for your module, can also be a function returning those
  defaults: {},
  // Shorthand sugar to register Nuxt hooks
  hooks: {},
  // The function holding your module logic, it can be asynchronous
  setup(moduleOptions, nuxt) {
  
      console.log('Hello from the module!')
      
  }
})

We’re getting into all the details in our course “Nuxt Modules: The Ultimate Guide” on Vue School.

Advanced Module Features

Nuxt modules are more than just simple functions. They can access and modify the Nuxt configuration, register hooks, and even add plugins. Let’s extend our module to demonstrate these capabilities.

Modifying Nuxt Configuration

Modules can directly modify the Nuxt configuration. For instance, let’s disable the Nuxt Devtools option from within our module. This option in enabled by default for freshly installed apps

  1. Update first-module.ts:
    // modules/first-module.ts
    
    export default defineNuxtModule({
      meta: {
        name: 'first-module',
        configKey: 'firstModule',
        compatibility: {
          nuxt: '>=3.0.0'
        }
      },
      defaults: {},
      setup(moduleOptions, nuxt) {
      
        console.log('Devtools enabled by default');
        nuxt.options.devtools.enabled = false;
        console.log('Devtools is disabled now');
        
      }
    })
    
  2. Restart the development server to see the changes take effect. If we run the app in our browser, we’ll notice that the Nuxt Devtools is disabled now.

Adding Plugins

Plugins are a powerful way to extend the functionality of your Nuxt application. To inject a Nuxt plugin from within a module, we need to follow the below steps:

  1. Create a runtime directory inside the modules directory and add a file named plugin.ts . The runtime directory is our way to pass files from the module to the application’s runtime.
    // modules/runtime/plugin.ts
    
    export default defineNuxtPlugin(() => {
      return {
        provide: {
          hello: (msg: string) => `Hello ${msg}!`
        }
      }
    })
    
  2. Update first-module.js to import the addPlugin and createResolver utilities from @nuxt/kit and include the plugin:
    // modules/first-module.ts
    
    import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'
    
    export default defineNuxtModule({
      meta: {
        name: 'first-module',
        configKey: 'firstModule',
        compatibility: {
          nuxt: '>=3.0.0'
        }
      },
      defaults: {},
      setup(moduleOptions, nuxt) {
      
          const { resolve } = createResolver(import.meta.url)
          
        addPlugin(resolve('./runtime/plugin'))
        
      }
    })
    
  3. Use the plugin in your application. Open App.vue and add the following:
    <template>
        <div>
            <h1>{{ $hello('world!') }}</h1>
        </div>
    </template>
    
    <script setup lang="ts">
        const { $hello } = useNuxtApp()
    </script>
    
  4. Restart the development server and open the browser console. You should see the heading "Hello world!" logged.

Publishing a Nuxt Module

When you’re focused on a specific app and the logic for the module is only needed there, local modules work just fine. However, if you aim to use a module across multiple apps or contribute to the Nuxt modules ecosystem, publishing your module is the way to go.

The process is a bit different from working with local modules, but Nuxt provides a fantastic starter template that simplifies the process. Instead of preparing an npm package from scratch, the template takes care of most of the boilerplate work for you.

Setting Up the Module for Publication

Nuxt provides a starter template for creating and publishing modules, making the process much simpler.

  1. Install the starter template outside of the Nuxt App:
    npx nuxi init -t module my-nuxt-module
    cd my-nuxt-module
    

This command sets up a new directory with a structure specifically designed for developing a Nuxt module.

  1. The template sets up a directory structure with everything you need to develop, test, and publish your module. Let’s take a look at the key components:
    • package.json: Contains metadata and dependencies for your module.
    • src: The source code for your module.
    • test: Basic tests using Vitest.
    • playground: A Nuxt app to test your module.
  2. Open src/module.ts and define your module:
    import { defineNuxtModule } from '@nuxt/kit'
    
    export default defineNuxtModule({
        meta: {
            name: 'my-nuxt-module',
            configKey: 'myModule',
        },
        defaults: {},
        setup (moduleOptions, nuxt) {
            nuxt.options.devtools.enabled = false
            console.log('Devtools disabled')
        }
    })
    

This code sets up a basic module that logs the module options and disables devtools.

  1. Test the module using the playground directory, which is a fully functional Nuxt application set up for this purpose. Running the development server with the dev command will launch the Nuxt app in the playground, allowing you to ensure that your module works as expected.
    npm run dev
    
  2. Build the module:
    npm run build
    
  3. Once you are satisfied with your module, publish it to npm:
    npm login
    npm run release
    

With that, any developer can install your module in their Nuxt app and register it to their nuxt.config.ts file.

export default defineNuxtConfig({
  modules: [
    MyModule
  ]
})

Conclusion

Nuxt modules offer a powerful way to extend and customize your Nuxt applications. By encapsulating functionality into reusable modules, you can keep your codebase clean, maintainable, and scalable. Whether you are developing local modules for a specific project or publishing modules for the wider community, Nuxt’s modular architecture and tooling make the process straightforward and enjoyable.

Remember, the key to mastering Nuxt modules is practice and exploration. As you work on different projects, try to identify common patterns and functionalities that can be abstracted into modules. This approach will not only improve your coding skills but also make your projects more modular and easier to manage.

Mostafa Said
Mostafa is a full-stack developer, a full-time Instructor at Vue School, and a Vue.js Jedi.

Follow MasteringNuxt on