Nuxt Layers

Nuxt Layers

What a layer is, why a frontend team standardises on them, and the mental model that makes every other page in this section obvious.

A layer is a Nuxt project fragment that another Nuxt project extends. Structurally it is an ordinary Nuxt app directory (nuxt.config.ts, app/components/, app/composables/, server/, app/app.config.ts); the consuming app pulls it in with extends or by placing it in layers/, and Nuxt treats the two as one application: every layer's directories are scanned, every layer's config is deep-merged, and the project always wins.

For a team, that is the mechanism behind "every app starts from the same place". A base layer carries the design system, the shared nuxt.config preset (modules, ESLint, fonts, icons, route rules) and the composables everyone needs; feature layers add auth, analytics or a CMS integration; each product app extends what it needs and overrides by placing a file at the same path. The role you are interviewing for is to design, publish and maintain exactly those layers, so this section is the spine of the guide and the module content is its supporting cast.

Know

  • Every Nuxt app is already a layer. The project itself is the first entry of nuxt.options._layers; extends just appends more of them. That is why a layer's directory structure is identical to an app's, and why the layer starter template ships a .playground/ app that extends it.
  • Three sources: a local path ('../base', './layers/base'), an npm package ('@team/nuxt-layer-base'), or a git repository fetched with giget ('github:team/layer#v1.2.0'). Local layers/* folders are auto-registered since Nuxt 3.12; git and npm layers must be listed in extends.
  • What a layer ships: components, composables, utils, pages, layouts, middleware, plugins, server/ routes and middleware, nuxt.config.ts (including modules and runtimeConfig), app.config.ts, public/ assets, i18n messages, type declarations. Anything Nuxt discovers by convention.
  • What a layer does not do: run code at build time. It declares; a module acts. A layer can list modules in its nuxt.config (that is how it ships a preset), and Nuxt deduplicates modules declared by several layers.
  • Merging: c12 loads each layer's nuxt.config, then everything is merged with defu: objects deep-merge, arrays concatenate, and the higher-priority layer's scalar wins. The same rule applies to app.config.
  • Priority, highest to lowest: project files → auto-scanned layers/ folders (alphabetical, so Z beats A) → extends entries in order (first beats second). Two layers defining app/components/Hero.vue is not an error; the higher one silently wins.
  • Paths inside a layer must be resolved relative to the layer (import.meta.url), because ~ and @ resolve against the consuming project. This is the single most common layer bug.

The three-part team toolkit

The shape that keeps coming back in senior interviews, and the one this guide assumes:

PackageKindShips
@team/nuxt-layer-baselayernuxt.config preset, app.config theme tokens, design-system components, shared composables, ESLint/TS conventions
@team/nuxt-layer-authlayerauth pages, middleware, session composables, server/api/auth/*
@team/nuxt-toolkitmodulebuild-time machinery: generated types, virtual files, transforms, hooks, DevTools tab

Layers ship app code and conventions; modules ship build-time behaviour and injected runtime. A company toolkit is usually both, and the layer lists the module in its modules array so consumers get everything from one extends entry.

This repository is the running example

This app extends a real layer: layers/base holds the Nuxt UI module registration, the CSS entry (resolved with import.meta.url), the fonts and icon configuration, the app.config colour tokens and the callout components used on these pages. The project's app/app.config.ts overrides one value from the layer (site.name), which you can see in the sidebar. Open those files while reading the next pages; every rule below is visible there.

Be able to say· What is a Nuxt layer and when do you reach for one?

"A layer is a partial Nuxt app that other apps extend. It ships conventions and app code: config presets, components, composables, pages, server routes, app.config. Nuxt scans every layer's directories and deep-merges every layer's config, with the project winning and earlier layers beating later ones, so a consuming app inherits everything and overrides by placing a file at the same path. I reach for a layer when I want to standardise how apps are built and look; when I need something to happen at build time, generated code or a Vite transform, that is a module, and a team toolkit is usually a layer that lists the module."

Gotcha· A layer is not a module

Candidates often describe layers as "modules with files". The difference is where the code runs: a module's setup() runs in Node at build time and mutates nuxt.options; a layer never runs, it is merged. If you catch yourself wanting an if in a layer, you want a module, or a nuxt.config option the consumer sets.

Exercise

Exercise

Create a fresh app with npm create nuxt -- --template layer nuxt-team-base, read every file it generates, and write down which directory each one would be scanned into by a consuming app. Then create a second app, add extends: ['../nuxt-team-base'], and run nuxt dev with debug: true to see the layer appear in the resolved _layers.

Pages in this section

  1. 01Anatomy of a layerA layer is a Nuxt app directory that another app merges in. What goes where, how Nuxt resolves its srcDir, and how to see the resolved layer list.
  2. 02extends and layer sourcesThe three places a layer can come from, the giget syntax for git layers, private repositories, and the auto-registered layers/ directory.
  3. 03Priority and mergingWhich layer wins when two define the same file or option, how c12 and defu merge configs, and how to prove the order instead of memorising it.
  4. 04Paths and aliases inside a layerWhy ~ and @ break inside a layer, the import.meta.url pattern, the
  5. 05Config merging in practiceHow modules, runtimeConfig, app.config, route rules, Vite options and environment overrides behave when a layer and a project both declare them.
  6. 06Overriding what a layer shipsHow a project replaces, wraps, extends or removes components, pages, layouts, composables, plugins, middleware and server routes inherited from a layer.
  7. 07Modules in layersLayers as module presets, how Nuxt deduplicates modules across layers, how module options merge, and how module authors make their modules layer-aware.
  8. 08Server code and Nitro in layersWhat a layer can ship under server/ and shared/, how Nitro merges handlers and config across layers, and why every route you ship is a security decision for every app.
  9. 09Publishing and consuming a layerThe layer starter and its playground, npm packaging rules, workspace versus registry versus git tags, the dev experience of each, and what counts as a breaking change.
  10. 10Testing a layer and CIThe playground as a test bench, fixture apps that extend the layer, asserting that overrides win, type-checking, and a CI matrix that catches Nuxt version skew before consumers do.
  11. 11Layers vs modules, and layers as architectureThe decision rule, the cases where a team needs both, domain-driven design with one layer per domain, and the places where a layer is the wrong tool.
  12. 12Pitfalls catalogueEighteen ways layers go wrong in practice, each with the symptom you will see, the cause underneath and the fix, plus code for the six that cost the most time.
  13. 13Designing a team layerThe senior-craft page for layers - defining a small public surface, theming through app.config, override recipes, performance and security costs per app, governance, and rolling out breaking changes.