Nuxt Layers

extends and layer sources

The three places a layer can come from, the giget syntax for git layers, private repositories, and the auto-registered layers/ directory.

extends is the single config option that turns an app into a consumer of layers. Nuxt hands the list to c12, which resolves each entry, downloads remote ones with giget, loads every layer's nuxt.config, and merges the results. Interviewers ask about the sources because each one has a different operational story: a local path hot-reloads, an npm package is versioned, a git reference needs authentication and a cache.

Know

  • Three sources, one array:
    nuxt.config.ts
    export default defineNuxtConfig({
      extends: [
        '../base',                          // local path, relative to this config file
        '@team/nuxt-layer-auth',            // npm package (resolved from node_modules)
        'github:team/nuxt-layer-analytics#v2.1.0', // git via giget
      ],
    })
    
  • Local paths resolve relative to the project's rootDir. Anything under ~~/layers/ does not even need to be listed: since Nuxt 3.12 every subdirectory of layers/ that has a nuxt.config.ts is registered automatically, and since 3.16 it gets a #layers/<folder> alias.
  • npm packages are referenced by name. The package's main must point at its nuxt.config.ts, and the layer's runtime dependencies must be in its dependencies, because consumers install them transitively.
  • Git sources use giget's syntax: github:owner/repo, github:owner/repo/sub/dir, github:owner/repo#branch-or-tag, plus gitlab: and bitbucket:. No ref means main. Options go in a tuple:
    nuxt.config.ts
    export default defineNuxtConfig({
      extends: [
        ['github:team/nuxt-layer-private#v1.4.0', {
          install: true,                       // run the package manager for the layer's dependencies
          auth: process.env.GITHUB_TOKEN,      // or set GIGET_AUTH in the environment
          meta: { name: 'private' },           // gives the layer a name -> #layers/private
        }],
      ],
    })
    

    GIGET_AUTH=<token> works without touching the config; GIGET_GITHUB_URL / GIGET_GITLAB_URL point giget at self-hosted instances.
  • Remote layers are downloaded, not installed. Their code is cached and merged like any other layer, but their node_modules are not yours: "if you are extending a remote source as a layer, you will not be able to access its dependencies outside of Nuxt". That is why install: true exists and why teams eventually move to npm for anything with dependencies.
  • A single string works too (extends: '../base'), and the array order matters: the first entry has the highest priority among the extended layers (details on the next page).

How it works

Which source fits which stage of a team's layer story:

StageSourceWhyWhat bites
Prototype in one repolayers/base (auto) or '../base'zero setup, hot reload, one PR changes layer and appnothing enforces a version boundary
Monorepo, several appspnpm workspace package @team/nuxt-layer-base (workspace:*)still hot-reloads, versioned in one lockfile, publishable laterapps must upgrade together unless you publish
Many repos, private registrynpm @team/nuxt-layer-base@^2real semver, changelog, Renovate PRsneeds a registry and a release pipeline
Many repos, no registrygithub:team/nuxt-layer-base#v2.3.0tags give versions for freetokens in CI, install: true, cache invalidation
Gotcha· Pinned tag, moved tag

c12 caches a git layer by its source string. If someone force-moves the v2.3.0 tag, consumers keep the old download until the cache is cleared. Treat tags as immutable, or extend by commit hash for anything that must be reproducible.

Verify before the interview:

Where c12 stores downloaded layers (it uses a directory under node_modules/.c12/) and how to invalidate it. Confirm the exact path in the c12 README before claiming it.

docs ↗

Exercise

Exercise
  • In a scratch app, create layers/base/nuxt.config.ts and confirm it is picked up with no extends entry (log _layers from a local module).
  • Move the same folder to ../base-outside and add extends: ['../base-outside']; confirm it is still one layer, not two.
  • Push it to a private GitHub repo, tag v0.1.0, and extend it as github:you/base-outside#v0.1.0 with GIGET_AUTH set. Delete the token and watch the error you get, so you recognise it later.

Be able to say

Be able to say· Where can a layer come from, and which source would you pick for a team?

"Three sources: a local path, an npm package, or a git reference fetched by giget, all listed in extends; folders under layers/ are picked up automatically. For a team I would start in a pnpm workspace so layer and apps move together with hot reload, then publish to the internal registry once more than a couple of repos consume it, because npm gives us semver, a changelog and Renovate. Git tags work without a registry, but you pay with tokens in CI, install: true for dependencies, and a cache you have to understand."