Nuxt Layers

Pitfalls catalogue

Eighteen 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.

Interviewers love "a consumer reports X, what do you check?" because it tests whether you have operated layers, not just built one. The table below is ordered roughly by how often each pitfall shows up in a team that has three or more apps on a shared layer. Learn the symptom → cause mapping; the fixes follow from the rules in the earlier pages.

Know

#SymptomCauseFix
1CSS or asset "not found", or the consumer's file is picked up instead of the layer's~/@ in the layer's nuxt.config resolve against the projectresolve from import.meta.url (details)
2The layer does nothing, no errorno nuxt.config.ts in the layer folderadd one, even empty
3Layer's runtime defaults ignored, secrets undefinedthe layer's .env is never loaded; only the project's isdefaults in runtimeConfig, values from each app's environment
4Layer components unstyled after installing from npmTailwind v4 skips node_modules when detecting classes@source "../node_modules/@team/nuxt-layer-base";
5Wrong component renders, "duplicate component" warningtwo layers resolve the same component nameprefix the layer's components, check components:extend
6An SDK initialises twice, events doubleplugins from every layer run; only same-path files overridemake layer plugins switchable, document them
7An override works locally, not in another appdifferent layer order (layers/ alphabetical, extends first-wins)numeric prefixes, explicit extends
8Cannot find package … with a git layerremote layer dependencies are not installed in the projectinstall: true, or publish to npm with declared dependencies
9Layer's app/components not scanned, or scanned twiceNuxt 3 layout vs Nuxt 4 app/ layout mixed, or a manual components entry duplicating the scanone layout; do not re-register scanned dirs
10Odd failures after bumping the layerNuxt version skew: the layer uses an API newer than the app's NuxtpeerDependencies.nuxt, CI on the lowest version
11Consumers keep getting old code from a git layergiget cache keyed by source string; tag was movedimmutable tags or commit hashes; clear the cache
12Property 'team' does not exist on type AppConfig in consumersAppConfigInput augmentation missing, or .d.ts not in the published filesship and include the augmentation
13Two stylesheets, doubled CSScss arrays concatenate; the app "overrode" the layer's entrysingle CSS entry in the layer, theme via app.config
14Layer's app.vue ignoredthe project has its own app.vueexpected; document the required shell
15NUXT_PUBLIC_TEAM_BETA=true arrives as a string or not at allno default for the key in runtimeConfig, so no coercion or overridedeclare typed defaults for every key
16Cannot remove a route the layer shipspages are additivepages:extend filter in the project
17Storage/cache path breaks in productionrelative path in layer's nitro.storageresolve from import.meta.url or from nuxt.options.rootDir
18Edits to a published layer do not hot-reloadnode_modules are not watchedworkspace:* link or a local extends path while developing

How it works

The six that burn the most hours, with the fix as code.

1 · Aliases

layers/base/nuxt.config.ts
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'

const currentDir = dirname(fileURLToPath(import.meta.url))

export default defineNuxtConfig({
  // ✗ css: ['~/assets/css/main.css']   -> resolves inside the consuming project
  css: [join(currentDir, 'app/assets/css/main.css')],
})

4 · Tailwind sources for an npm layer

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";
/* Tailwind v4 ignores node_modules during automatic detection */
@source "../../../node_modules/@team/nuxt-layer-base";

5 · Name collisions

layers/base/nuxt.config.ts
export default defineNuxtConfig({
  components: [
    // Scan our components with a stable prefix: Button.vue -> <TeamButton>, Card/Header.vue -> <TeamCardHeader>
    { path: join(currentDir, 'app/components'), prefix: 'Team' },
  ],
})

6 · Switchable plugins

layers/base/app/plugins/analytics.client.ts
export default defineNuxtPlugin({
  name: 'team-analytics',
  setup() {
    const { team } = useAppConfig()
    if (!team.analytics?.enabled) return          // opt-in through app.config; no double init
    // initialise the SDK once per client session
  },
})

12 · Types that travel with the layer

layers/base/app/types/app-config.d.ts
declare module 'nuxt/schema' {
  interface AppConfigInput {
    team?: { brand?: string, analytics?: { enabled?: boolean } }
  }
}
export {}
layers/base/package.json
{ "files": ["nuxt.config.ts", "app", "server", "shared", "public"] }

15 · Typed runtime defaults

layers/base/nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      teamBeta: false,          // boolean default -> NUXT_PUBLIC_TEAM_BETA=true is coerced to true
      teamApiBase: 'https://api.internal',
    },
  },
})
Gotcha· The consumer's report is usually about a different layer

"Your layer broke my app" often means the app extended a second layer that shadows yours, or the app's own layers/ folder sorts above it. Ask for the resolved order first (a console.log(nuxt.options._layers.map(l => l.cwd)) in a local module), then debug.

Gotcha· It works in the playground

Pitfalls 1, 3, 4, 9 and 18 are invisible inside the layer's repository. A fixture outside the layer folder, or a real consuming app in CI, is the only way to catch them before release; see Testing and CI.

Verify before the interview:

Whether the current docs describe where remote layers are cached and how to clear it, and whether install: true also runs for npm-hosted layers (it is documented for git sources).

docs ↗

Exercise

Exercise
  • Reproduce pitfalls 1, 5, 6 and 15 in a scratch layer + app, one commit each. For each, write down the exact error or symptom text you saw; interviewers remember specific observations.
  • Publish the scratch layer to a local Verdaccio and reproduce pitfall 4. Fix it with @source.
  • Write the "Troubleshooting" section of the layer README from this table, in your own words.

Be able to say

Be able to say· A consumer says a layer component renders unstyled and a route from the layer is missing. What do you check?

"Unstyled points at Tailwind source detection: if they installed the layer from npm, Tailwind never scanned node_modules, so I check for the @source line in their CSS entry. A missing route is almost always priority: another layer or their own layers/ folder resolves the same path, or they redefined the page; I ask for the resolved _layers order and look at components:extend and the generated routes. Before either, I confirm the layer even loaded: a folder without nuxt.config.ts is ignored silently. Most layer bugs are one of these three: paths, order, or not loaded."