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.
| # | Symptom | Cause | Fix |
|---|---|---|---|
| 1 | CSS 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 project | resolve from import.meta.url (details) |
| 2 | The layer does nothing, no error | no nuxt.config.ts in the layer folder | add one, even empty |
| 3 | Layer's runtime defaults ignored, secrets undefined | the layer's .env is never loaded; only the project's is | defaults in runtimeConfig, values from each app's environment |
| 4 | Layer components unstyled after installing from npm | Tailwind v4 skips node_modules when detecting classes | @source "../node_modules/@team/nuxt-layer-base"; |
| 5 | Wrong component renders, "duplicate component" warning | two layers resolve the same component name | prefix the layer's components, check components:extend |
| 6 | An SDK initialises twice, events double | plugins from every layer run; only same-path files override | make layer plugins switchable, document them |
| 7 | An override works locally, not in another app | different layer order (layers/ alphabetical, extends first-wins) | numeric prefixes, explicit extends |
| 8 | Cannot find package … with a git layer | remote layer dependencies are not installed in the project | install: true, or publish to npm with declared dependencies |
| 9 | Layer's app/components not scanned, or scanned twice | Nuxt 3 layout vs Nuxt 4 app/ layout mixed, or a manual components entry duplicating the scan | one layout; do not re-register scanned dirs |
| 10 | Odd failures after bumping the layer | Nuxt version skew: the layer uses an API newer than the app's Nuxt | peerDependencies.nuxt, CI on the lowest version |
| 11 | Consumers keep getting old code from a git layer | giget cache keyed by source string; tag was moved | immutable tags or commit hashes; clear the cache |
| 12 | Property 'team' does not exist on type AppConfig in consumers | AppConfigInput augmentation missing, or .d.ts not in the published files | ship and include the augmentation |
| 13 | Two stylesheets, doubled CSS | css arrays concatenate; the app "overrode" the layer's entry | single CSS entry in the layer, theme via app.config |
| 14 | Layer's app.vue ignored | the project has its own app.vue | expected; document the required shell |
| 15 | NUXT_PUBLIC_TEAM_BETA=true arrives as a string or not at all | no default for the key in runtimeConfig, so no coercion or override | declare typed defaults for every key |
| 16 | Cannot remove a route the layer ships | pages are additive | pages:extend filter in the project |
| 17 | Storage/cache path breaks in production | relative path in layer's nitro.storage | resolve from import.meta.url or from nuxt.options.rootDir |
| 18 | Edits to a published layer do not hot-reload | node_modules are not watched | workspace:* link or a local extends path while developing |
The six that burn the most hours, with the fix as code.
1 · Aliases
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
@import "tailwindcss";
@import "@nuxt/ui";
/* Tailwind v4 ignores node_modules during automatic detection */
@source "../../../node_modules/@team/nuxt-layer-base";
5 · Name collisions
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
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
declare module 'nuxt/schema' {
interface AppConfigInput {
team?: { brand?: string, analytics?: { enabled?: boolean } }
}
}
export {}
{ "files": ["nuxt.config.ts", "app", "server", "shared", "public"] }
15 · Typed runtime defaults
export default defineNuxtConfig({
runtimeConfig: {
public: {
teamBeta: false, // boolean default -> NUXT_PUBLIC_TEAM_BETA=true is coerced to true
teamApiBase: 'https://api.internal',
},
},
})
"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.
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.
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).
@source."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."
Layers vs modules, and layers as architecture
The 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.
Designing a team layer
The 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.