Mastering Nuxt Layers: A Complete Guide to Scalable Nuxt 3 Architecture

By Vantol Bennett
Author
Mastering Nuxt Layers
Introduction#
Nuxt 3 introduced many powerful features, but Nuxt Layers stand out as one of the most transformative. Layers allow you to build applications by composing reusable Nuxt projects, instead of maintaining large monolithic codebases or copying boilerplate across repositories.
If you’ve ever wanted to:
- Reuse layouts, components, and pages across projects
- Build a scalable SaaS architecture
- Maintain a shared design system or feature set
Then Nuxt Layers are exactly what you’re looking for.
This guide is written as a long-form tutorial. You can follow along step by step and apply everything directly to real projects.
What Are Nuxt Layers?#
A Nuxt Layer is a Nuxt application that is designed to be extended, not deployed on its own.
In simple terms:
- A layer looks like a normal Nuxt app
- Another Nuxt app can extend it
- Nuxt merges everything together at runtime
Layers can contain:
- Pages
- Components
- Layouts
- Composables
- Assets
- Configuration
- Dependencies
Think of layers as inheritance for Nuxt applications.
Why Nuxt Layers Matter#
Before layers, reuse often meant duplication. Layers introduce a first-class architectural pattern for sharing functionality.
Benefits of Using Layers#
- Reusable features across multiple apps
- Cleaner separation of concerns
- Faster project setup
- Easier long-term maintenance
- Ideal for SaaS platforms and white-label apps
Layers help teams move faster without sacrificing structure.
How Nuxt Layers Work#
Nuxt merges layers from bottom to top:
- Base layers (design system, shared config)
- Feature layers (auth, billing, dashboards)
- Final application (branding, custom logic)
If multiple layers define the same file, the closest one wins.
Creating Your First Nuxt Layer#
Step 1: Create the Layer#
npx nuxi init layers/base-ui
cd layers/base-ui
npm install
This creates a standard Nuxt project structure:
layers/base-ui/
├─ components/
├─ layouts/
├─ composables/
├─ assets/
├─ nuxt.config.ts
You will not run this project directly—it exists to be extended.
Step 2: Configure the Layer#
// layers/base-ui/nuxt.config.ts
export default defineNuxtConfig({
components: true,
css: ['~/assets/main.css']
})
Add a shared component:
<!-- layers/base-ui/components/BaseButton.vue -->
<template>
<button class="btn">
<slot />
</button>
</template>
<style scoped>
.btn {
padding: 0.75rem 1.25rem;
border-radius: 0.5rem;
background: black;
color: white;
}
</style>
Using a Layer in a Nuxt App#
Step 3: Create the App#
npx nuxi init apps/web
cd apps/web
npm install
Extend the layer:
// apps/web/nuxt.config.ts
export default defineNuxtConfig({
extends: ['../layers/base-ui']
})
Now you can use the shared component without importing it:
<template>
<BaseButton>
Click Me
</BaseButton>
</template>
Using Multiple Layers#
You can extend multiple layers in a single app.
export default defineNuxtConfig({
extends: [
'../layers/base-ui',
'../layers/auth',
'../layers/dashboard'
]
})
Later layers override earlier ones.
Pages Inside Layers#
Layers can define pages just like an app.
layers/auth/pages/login.vue
That page automatically becomes available in the app.
To override it:
apps/web/pages/login.vue
Nuxt will use the app’s version instead.
Layouts in Layers#
Shared layouts are ideal for base UI.
<!-- layers/base-ui/layouts/default.vue -->
<template>
<div>
<header>Base Header</header>
<slot />
</div>
</template>
All extending apps inherit this layout automatically.
Composables in Layers#
Layers are perfect for shared logic.
// layers/auth/composables/useAuth.ts
export const useAuth = () => {
const user = useState('user', () => null)
const login = async () => {
user.value = { name: 'Vantol' }
}
return { user, login }
}
This composable is globally available.
Runtime Config and Environment Variables#
Layers can define runtime configuration:
export default defineNuxtConfig({
runtimeConfig: {
public: {
appName: 'Base App'
}
}
})
Apps can override these values safely.
Dependencies in Layers#
Layers may include their own dependencies:
cd layers/base-ui
npm install tailwindcss
Dependencies are merged into the final build.
Be mindful—shared dependencies affect every extending app.
Recommended Monorepo Structure#
.
├─ apps/
│ ├─ web
│ └─ admin
├─ layers/
│ ├─ base-ui
│ ├─ auth
│ ├─ billing
│ └─ dashboard
This structure works well with pnpm workspaces, Turborepo, or Nx.
Real-World Example: SaaS Starter#
A common production setup:
base-ui– Design systemauth– Authentication and guardsbilling– Stripe and subscriptionsdashboard– Core product UI
extends: [
'../layers/base-ui',
'../layers/auth',
'../layers/billing',
'../layers/dashboard'
]
New apps can be launched in days instead of weeks.
Overriding Behavior Safely#
You can override:
- Components
- Pages
- Layouts
- Composables
Nuxt resolves conflicts using closest-first resolution.
Common Pitfalls#
- Putting app-specific logic in base layers
- Creating tight coupling between layers
- Ignoring layer order
- Treating layers like plugins
Design layers as products, not shortcuts.
Layers vs Nuxt Modules#
| Feature | Layers | Modules |
|---|---|---|
| Pages & layouts | Yes | No |
| File-system reuse | Yes | No |
| App architecture | Yes | No |
| Runtime hooks | Limited | Yes |
They solve different problems and often work best together.
When You Should (and Shouldn’t) Use Layers#
Use layers when:
- You manage multiple Nuxt apps
- You want shared features or UI
- You’re building a SaaS platform
Avoid layers when:
- You have a single small app
- There is little to no shared logic
Conclusion#
Nuxt Layers unlock a new level of scalability and maintainability for Nuxt 3 applications. When designed intentionally, they allow teams to move faster, share more, and maintain cleaner architectures over time.
If you’re serious about building scalable Nuxt applications, mastering layers is no longer optional—it’s essential.
Happy building 🚀
Share this post
Stay Updated
Get the latest posts delivered straight to your inbox.
![Adding environment variables to the runtime in Nuxt3 [Beta]](https://res.cloudinary.com/ddszyeplg/image/upload/v1642350413/vantol/black-text_emxagi.png)
