Conrad Nuxt

Modules, plugins and layers

Module versus plugin, what a module can do with @nuxt/kit, build-time, app and Nitro hooks, an observability module with a provider option, layers and their override order, and when a platform ships a layer or a module.

From the module, plugin and layer parts of your Nuxt note. The full module-author material is in Module authoring and Nuxt Layers.

Know

  • Module: build-time code in Node (defineNuxtModule: meta, defaults, setup, hooks) that edits nuxt.options, hooks into the build and registers runtime pieces with @nuxt/kit (addPlugin, addComponent, addImports, addServerHandler, addTemplate). Options reach runtime only through runtimeConfig or templates.
  • Plugin: runtime code that runs when the Nuxt app is created, per request on the server and once per page load in the browser; both sides unless .client/.server.
  • Hooks: Nuxt hooks at build time (pages:extend, modules:done), app hooks on nuxtApp at runtime (app:error, page:finish), Nitro hooks on nitroApp (request, error, afterResponse). A module reaches runtime hooks through a plugin it registers.
  • Layers: a Nuxt app other apps extend: components, pages, layouts, composables, server/, app.config, nuxt.config. Priority: the app, then layers/ (Z before A), then extends (first wins). Configs merge with defu.
  • Layer or module: layer for the overridable surface (theme, layouts, components to shadow), module for behaviour with options and logic; layers ship source compiled by every consumer, modules ship compiled code.

Fact check of your notes

Gotcha· A plugin without a suffix runs on both sides

"Plugin is bundled in the app, executes in browser (unless it has a .server suffix)": a plugin without a suffix runs on the server for every request and in the browser on page load, as the later part of the note says. .client limits it to the browser, .server to the server.

Gotcha· app:error is a runtime hook

The module example registers app:error in the module's hooks. Module hooks are build-time Nuxt hooks; app:error belongs to the running Nuxt app, so to react to it a module registers a plugin and calls nuxtApp.hook('app:error', …) there.

Exercise

Exercise
  • Build the observability module from the coding question in a local app with two fake providers, switch the provider in nuxt.config, and override the sample rate with NUXT_PUBLIC_OBSERVABILITY_SAMPLE_RATE.
  • Create a base layer with an AppHeader component and an app.config theme colour, extend it from an app, then override the header and the colour from the app.

Be able to say

Be able to say· What is the difference between a module and a layer?

"A module is code that runs at build time: it reads options and registers plugins, components, server routes or generated files, so it's the place for behaviour and logic. A layer is a Nuxt app that gets merged into the consumer: it never runs on its own, and the consumer can override any of its files or config. So I'd ship a theme, layouts and replaceable components as a layer, and things like observability or i18n setup as modules, often with the base layer installing the platform's modules."

Be able to say· How would a platform team make error tracking consistent across many Nuxt apps?

"One module every app installs, with an option for the provider, Sentry or Grafana. The module registers a plugin that loads only that SDK, hooks into Vue's and Nitro's error hooks, adds release and environment, waits for consent and samples, with the keys in runtime config. Apps only call one small composable, so switching providers is a config change and a fix ships to everyone in one release."

Your notes

Open in Notes

Nothing yet. Notes filed here show up on this page and the section overview.