Nuxt Crouton uses a two-layer architecture that separates generated code from the stable core library. This approach, combined with Nuxt's layer system, allows you to organize your code by business domain while maintaining flexibility and control.
The core principle behind Nuxt Crouton is the separation between your customizable generated code and the stable core library. This architecture gives you the freedom to modify generated files while benefiting from updates to the underlying framework.
┌─────────────────────────────────────┐
│ Generated Code (Yours) │
│ - Forms, Lists, Tables │
│ - You customize freely │
│ - Lives in YOUR project │
└─────────────────────────────────────┘
↓ uses
┌─────────────────────────────────────┐
│ Core Library (Stable) │
│ - Composables, utilities │
│ - Modal management, caching │
│ - Updates via npm │
└─────────────────────────────────────┘
The generated code layer includes all the CRUD interfaces you create using the Crouton generator:
This code lives in your project and is yours to customize however you need. You can modify components, add new features, change styling, or completely refactor the generated code—it's all under your control.
The core library provides the foundational utilities and composables that your generated code uses:
useCollectionQuery(), useCollectionMutation(), useCroutonMutate()useCrouton() with container type parameter (modal, slideover, dialog, inline)useNotify() for user feedbackuseFetchThe core library stays consistent and receives updates via npm. When you update the nuxt-crouton package, you get bug fixes and new features in the composables without affecting your customized code.
This architecture solves a common problem in code generation tools: how to provide updates without breaking customizations.
With Nuxt Crouton:
Nuxt layers allow you to organize your collections by business domain rather than technical function. This creates clear boundaries, improves maintainability, and enables domain-specific deployments.
Clear Boundaries - Each domain is isolated with its own components, composables, and API routes. Changes in one domain don't affect others.
Easier Maintenance - Related code stays together. When working on e-commerce features, everything you need is in the shop layer.
Independent Deployment - Deploy layers separately or together. This is particularly useful for larger applications or multi-tenant systems.
Reusability - Share layers across projects. Build a blog layer once, use it in multiple applications.
A typical Nuxt Crouton project using layers looks like this:
layers/
├── shop/ # E-commerce domain
│ └── collections/
│ ├── products/
│ │ ├── app/
│ │ │ ├── components/
│ │ │ │ ├── _Form.vue
│ │ │ │ └── List.vue
│ │ │ └── composables/
│ │ │ └── useShopProducts.ts
│ │ ├── server/
│ │ │ ├── api/teams/[id]/shop-products/
│ │ │ └── database/
│ │ │ └── schema.ts
│ │ └── types.ts
│ ├── orders/
│ └── inventory/
│
├── blog/ # Content domain
│ └── collections/
│ ├── posts/
│ ├── authors/
│ └── comments/
│
└── admin/ # Admin domain
└── collections/
├── users/
└── roles/
Use layers when you have:
Don't use layers for:
Start simple—you can always add layers later as your application grows.
To generate collections into a specific layer, pass the layer as the first positional argument:
# Generate into the shop layer
npx crouton-generate shop products --fields-file schemas/products.json
# Generate into the blog layer
npx crouton-generate blog posts --fields-file schemas/posts.json
# Generate into the admin layer
npx crouton-generate admin users --fields-file schemas/users.json
The layer is a required positional argument (not a flag). If you omit both layer and collection, Crouton looks for a crouton.config.js file instead.
Each layer can have its own nuxt.config.ts file for layer-specific configuration:
// layers/shop/nuxt.config.ts
export default defineNuxtConfig({
// Layer-specific configuration
components: {
dirs: [
{ path: '~/components', prefix: 'Shop' }
]
}
})
This allows you to:
Good - Organized by business domain:
layers/
├── shop/ # All e-commerce features
│ └── collections/
│ ├── products/
│ ├── orders/
│ └── inventory/
└── blog/ # All content features
└── collections/
├── posts/
├── authors/
└── comments/
Bad - Organized by technical function:
components/
├── forms/ # All forms together
├── lists/ # All lists together
└── tables/ # All tables together
Everything related to a domain should live in that domain's layer:
This makes it easy to find code, understand dependencies, and make changes without affecting other domains.
shop, blog, admin (lowercase, singular or plural based on domain)products, orders, posts (plural)_Form.vue, List.vue (generated per collection)useShopProducts, useShopOrders (camelCase, layer prefix + collection)If one layer depends on another, document it clearly:
// layers/shop/README.md
# Shop Layer
E-commerce functionality for products, orders, and inventory.
## Dependencies
- Requires `admin` layer for user management
- Uses shared types from `core` layer