Authoring Nuxt Layers
Nuxt layers are a powerful feature that you can use to share and reuse partial Nuxt applications within a monorepo, or from a git repository or npm package. The layers structure is almost identical to a standard Nuxt application, which makes them easy to author and maintain.
A minimal Nuxt layer directory should contain a nuxt.config.ts file to indicate it is a layer.
export default defineNuxtConfig({})
Additionally, certain other files in the layer directory will be auto-scanned and used by Nuxt for the project extending this layer.
components/*- Extend the default componentscomposables/*- Extend the default composableslayouts/*- Extend the default layoutsmiddleware/*- Extend the default middlewarepages/*- Extend the default pagesplugins/*- Extend the default pluginsutils/*- Extend the default utilsapp.config.ts- Extend the default app configserver/*- Extend the default server endpoints & middlewarenuxt.config.ts- Extend the default nuxt config
Basic Example
export default defineNuxtConfig({
extends: [
'./base',
],
})
Layer Priority
When extending from multiple layers, it's important to understand the override order. Layers with higher priority override layers with lower priority when they define the same files or components.
The priority order from highest to lowest is:
- Your project files - always have the highest priority
- Auto-scanned layers from
~~/layersdirectory - sorted alphabetically (Z has higher priority than A) - Layers in
extendsconfig - first entry has higher priority than second
When to Use Each
extends- Use for external dependencies (npm packages, remote repositories) or layers outside your project directory~~/layersdirectory - Use for local layers that are part of your project
~/layers/1.z-layer, ~/layers/2.a-layer. This way 2.a-layer will have higher priority than 1.z-layer.Example
export default defineNuxtConfig({
extends: [
// Local layer outside the project
'../base',
// NPM package
'@my-themes/awesome',
// Remote repository
'github:my-themes/awesome#v1',
],
})
If you also have ~~/layers/custom, the priority order is:
- Your project files (highest)
~~/layers/custom../base@my-themes/awesomegithub:my-themes/awesome#v1(lowest)
This means your project files will override any layer, and ~~/layers/custom will override anything in extends.
Starter Template
To get started you can initialize a layer with the nuxt/starter/layer template. This will create a basic structure you can build upon. Execute this command within the terminal to get started:
npm create nuxt -- --template layer nuxt-layer
Follow up on the README instructions for the next steps.
Publishing Layers
You can publish and share layers by either using a remote source or an npm package.
Git Repository
You can use a git repository to share your Nuxt layer. Some examples:
export default defineNuxtConfig({
extends: [
// GitHub Remote Source
'github:username/repoName',
// GitHub Remote Source within /base directory
'github:username/repoName/base',
// GitHub Remote Source from dev branch
'github:username/repoName#dev',
// GitHub Remote Source from v1.0.0 tag
'github:username/repoName#v1.0.0',
// GitLab Remote Source example
'gitlab:username/repoName',
// Bitbucket Remote Source example
'bitbucket:username/repoName',
],
})
GIGET_AUTH=<token> to provide a token.GIGET_GITHUB_URL=<url> or GIGET_GITLAB_URL=<url> environment variable - or directly configure it with the auth option in your nuxt.config.node_modules/.c12/layer_name/node_modules/) that is not accessible to your package manager.install: true in your layer options.export default defineNuxtConfig({
extends: [
['github:username/repoName', { install: true }],
],
})
npm Package
You can publish Nuxt layers as an npm package that contains the files and dependencies you want to extend. This allows you to share your config with others, use it in multiple projects or use it privately.
To extend from an npm package, you need to make sure that the module is published to npm and installed in the user's project as a devDependency. Then you can use the module name to extend the current nuxt config:
export default defineNuxtConfig({
extends: [
// Node Module with scope
'@scope/moduleName',
// or just the module name
'moduleName',
],
})
To publish a layer directory as an npm package, you want to make sure that the package.json has the correct properties filled out. This will make sure that the files are included when the package is published.
{
"name": "my-theme",
"version": "1.0.0",
"type": "module",
"main": "./nuxt.config.ts",
"dependencies": {},
"devDependencies": {
"nuxt": "^3.0.0"
}
}
dependencies. The nuxt dependency, and anything only used for testing the layer before publishing, should remain in the devDependencies field.Now you can proceed to publish the module to npm, either publicly or privately.
Tips
Named Layer Aliases
Auto-scanned layers (from your ~~/layers directory) automatically create aliases. For example, you can access your ~~/layers/test layer via #layers/test.
If you want to create named layer aliases for other layers, you can specify a name in the configuration of the layer.
export default defineNuxtConfig({
$meta: {
name: 'example',
},
})
This will produce an alias of #layers/example which points to your layer.
Relative Paths and Aliases
When importing using global aliases (such as ~/ and @/) in a layer components and composables, note that these aliases are resolved relative to the user's project paths. As a workaround, you can use relative paths to import them, or use named layer aliases.
Also when using relative paths in nuxt.config file of a layer, (with exception of nested extends) they are resolved relative to user's project instead of the layer. As a workaround, use full resolved paths in nuxt.config:
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'
const currentDir = dirname(fileURLToPath(import.meta.url))
export default defineNuxtConfig({
css: [
join(currentDir, './assets/main.css'),
],
})
Disabling Modules from Layers
When extending a layer, you might want to disable certain modules that it includes. You can do this by setting the module's config key to false in your Nuxt config.
export default defineNuxtConfig({
extends: ['./base-layer'],
// Disable modules from the layer by setting their config key to false
image: false, // Disables @nuxt/image
pinia: false, // Disables @pinia/nuxt
})
image for @nuxt/image, pinia for @pinia/nuxt, and content for @nuxt/content. Check the module's documentation for its specific config key.This is useful when:
- A layer includes modules you don't need in your project
- You want to use a different implementation than what the layer provides
- You need to disable analytics or other modules in specific environments
false will prevent its setup function from running while still generating types for the module.Multi-Layer Support for Nuxt Modules
You can use the getLayerDirectories utility from Nuxt Kit to support custom multi-layer handling for your modules.
import { defineNuxtModule, getLayerDirectories } from 'nuxt/kit'
export default defineNuxtModule({
setup (_options, nuxt) {
const layerDirs = getLayerDirectories()
for (const [index, layer] of layerDirs.entries()) {
console.log(`Layer ${index}:`)
console.log(` Root: ${layer.root}`)
console.log(` App: ${layer.app}`)
console.log(` Server: ${layer.server}`)
console.log(` Pages: ${layer.appPages}`)
// ... other directories
}
},
})
Notes:
- Earlier items in the array have higher priority and override later ones
- The user's project is the first item in the array
Going Deeper
Configuration loading and extends support is handled by unjs/c12, merged using unjs/defu and remote git sources are supported using unjs/giget. Check the docs and source code to learn more.