Frequently Asked Questions
useCollectionQuery patterns (basic, filtering, pagination, sorting, relations), see Querying Data.This page answers the most frequently asked questions about Nuxt Crouton. For detailed troubleshooting, see the Troubleshooting Guide.
Generation & Setup
Q: What fields are auto-generated and should NOT be in my schema?
A: Never define these fields in your schema files:
id- Always auto-generated (UUID or nanoid)createdAt,updatedAt,updatedBy- Generated whenuseMetadata: true(default)teamId,userId- Generated whenuseTeamUtility: true
Defining these manually causes duplicate key errors during build.
Common mistake:
{
"id": { "type": "string" }, // ❌ Remove
"createdAt": { "type": "date" }, // ❌ Remove
"teamId": { "type": "string" }, // ❌ Remove
"title": { "type": "string" } // ✅ Keep
}
See: Schema Format - Auto-Generated Fields
Q: How do I regenerate a collection without losing customizations?
A: Nuxt Crouton generates code in layers, which you can freely customize. Regeneration is safe as long as you:
- Keep custom components separate - Place them in subdirectories like
components/custom/ - Use slots for overrides - Override specific fields/columns via slots instead of editing generated files
- Commit before regenerating - Always commit working code before running the generator
# Safe regeneration workflow
git add .
git commit -m "Before regeneration"
npx crouton-generate config crouton.config.js products --force
See: Customization
Q: Should collection names be singular or plural?
A: Always use plural names:
# ✅ Correct
name: products
name: blogPosts
name: orderItems
# ❌ Wrong
name: product
name: blog_post
name: orderItem
See: Conventions - Collection Names
Q: What naming convention should I use for fields?
A: Use camelCase for all field names:
{
"firstName": { "type": "string" }, // ✅ Correct
"isActive": { "type": "boolean" }, // ✅ Correct
"publishedAt": { "type": "date" }, // ✅ Correct
"first_name": { "type": "string" }, // ❌ Wrong (snake_case)
"FirstName": { "type": "string" } // ❌ Wrong (PascalCase)
}
See: Conventions - Field Names
Data Operations
Q: Why isn't my data updating after save/delete?
A: This is usually a cache invalidation issue. Check:
- Collection name matches between query and mutation
- Using
useCollectionMutation()which auto-invalidates cache
// ✅ Correct - auto-invalidation
const { create, update } = useCollectionMutation('products')
await create({ title: 'New Product' })
// ❌ Wrong - manual invalidation needed
const { mutate } = useCroutonMutate()
await mutate('create', 'products', data)
await refreshNuxtData((key) => key.startsWith('collection:products:'))
See: Troubleshooting - Data Not Updating
Q: How do I handle loading and error states?
A: All query composables return pending and error properties. Use these to conditionally render loading spinners, error messages, and retry buttons. For the complete pattern, see Best Practices - Handle Loading States.
Q: When should I use useCollectionMutation() vs useCroutonMutate()?
A:
Use useCollectionMutation() for:
- Generated forms
- Repeated operations on same collection
- Multi-step wizards
- Bulk operations
Use useCroutonMutate() for:
- Quick toggle buttons
- One-off actions
- Different collections in same component
See: Best Practices - Choose the Right Mutation Method
Customization
Q: How do I customize a single form field?
A: Use the #field-[fieldName] slot:
<script setup lang="ts">
const { formData, save } = useCollectionForm('products')
</script>
<template>
<CroutonForm v-model="formData" @save="save">
<!-- Override price field -->
<template #field-price>
<CustomPriceField v-model="formData.price" />
</template>
</CroutonForm>
</template>
See: Customization - Custom Components
Q: How do I customize a table column?
A: Use the #column-[fieldName] slot:
<template>
<CroutonTable :data="products">
<template #column-status="{ row }">
<UBadge
:color="row.status === 'active' ? 'green' : 'gray'"
>
{{ row.status }}
</UBadge>
</template>
</CroutonTable>
</template>
See: Customization - Custom Columns
Q: Can I completely replace a generated component?
A: Yes, create a component with the same name in your layer:
layers/products/components/
└── CroutonForm.vue ← Your custom version
This overrides the generated component entirely.
TypeScript & Development
Q: Why am I getting "Cannot find module" errors after generation?
A: TypeScript server needs to be restarted:
In VS Code:
- Press
Cmd+Shift+P(Mac) orCtrl+Shift+P(Windows) - Type "Restart TS Server"
- Select "TypeScript: Restart TS Server"
Or clear cache:
rm -rf .nuxt
npx nuxt prepare
See: Troubleshooting - Type Errors
Q: How do I get type safety for queries?
A: Use TypeScript generics with useCollectionQuery<YourType>() to get full type safety. Import your type from the layer's types file and pass it as a generic parameter. See: Best Practices - Type Your Queries.
Q: Why aren't Tailwind classes working in layer components?
A: Tailwind v4 doesn't auto-scan node_modules. Add @source directive:
/* app/assets/css/tailwind.css */
@import "tailwindcss";
@import "@nuxt/ui";
/* Scan Nuxt Crouton layers */
@source "../../../node_modules/@friendlyinternet/nuxt-crouton*/app/**/*.{vue,js,ts}";
Then restart dev server:
pnpm dev
See: Troubleshooting - Tailwind Classes
Relations & References
Q: How do I define a relationship between collections?
A: Use reference field type with ref-target:
# posts.yml
fields:
- name: authorId
type: reference
ref-target: users # Target collection (plural)
- name: categoryIds
type: reference
ref-target: categories
multiple: true # Many-to-many
See: Patterns - Relations
Q: How do I query related data?
A: Use the include option in your query to load related data. See Querying with Relations for the complete pattern and Patterns - Relations for advanced usage.
Forms & Validation
Q: Why aren't validation errors showing?
A: Check that:
- Schema is passed to form:
:schema="schema" - Field names match schema keys
- State is reactive (
ref()orreactive())
<script setup lang="ts">
import { z } from 'zod'
const schema = z.object({
name: z.string().min(1, 'Required'),
price: z.number().min(0)
})
const state = ref({ name: '', price: 0 })
</script>
<template>
<UForm :state="state" :schema="schema" @submit="handleSubmit">
<UFormField label="Name" name="name">
<UInput v-model="state.name" />
</UFormField>
</UForm>
</template>
See: Troubleshooting - Validation Errors
Q: How do I create conditional fields?
A: Use v-if with reactive state:
<script setup lang="ts">
const productType = ref('physical')
</script>
<template>
<UFormField label="Type" name="type">
<USelect v-model="productType" :options="['physical', 'digital']" />
</UFormField>
<!-- Only show for physical products -->
<UFormField v-if="productType === 'physical'" label="Weight" name="weight">
<UInput v-model="formData.weight" type="number" />
</UFormField>
</template>
See: Patterns - Forms
Performance
Q: How do I optimize for large datasets?
A: Use these strategies:
- Implement pagination - See Querying with Pagination
- Use server-side filtering - Filter in your database, not the frontend
- Optimize relations - Use server-side joins instead of multiple queries
See: Troubleshooting - Performance Issues
Features
Q: Which features are production-ready?
A:
- Stable ✅ - Production-ready (Internationalization)
- Beta 🔬 - Safe for non-critical use (Rich Text, Maps, Connectors, DevTools)
- Experimental ⚠️ - Use with caution (Assets, Events)
See: Features Overview
Q: How do I enable internationalization (i18n)?
A:
- Extend the i18n layer:
// nuxt.config.ts
export default defineNuxtConfig({
extends: [
'@friendlyinternet/nuxt-crouton',
'@friendlyinternet/nuxt-crouton-i18n'
]
})
- Mark fields as translatable:
// crouton.config.js
export default {
translations: {
collections: {
products: ['name', 'description']
}
}
}
- Query with locale: Bind your query to the i18n locale reactively (see Querying with Filters for the pattern).
See: Internationalization
Deployment
Q: Do I need to regenerate code before deploying?
A: No, generated code is committed to your repository. Just deploy as normal:
pnpm build
Q: What environment variables do I need?
A: Depends on your setup:
Database:
DATABASE_URL- Database connection string
Team-based auth:
- Session/auth provider variables (e.g.,
NUXT_SESSION_SECRET)
Features:
- i18n:
NUXT_PUBLIC_I18N_DEFAULT_LOCALE - Assets: Storage provider credentials (S3, R2, etc.)
Check your layer's documentation for specific requirements.
Getting Help
Q: Where can I get help if my question isn't answered here?
A:
- Check Troubleshooting Guide for detailed solutions
- Search GitHub Issues for similar problems
- Ask in GitHub Discussions for general questions
- Create an issue with:
- Nuxt Crouton version
- Nuxt version
- Error messages
- Minimal reproduction steps
Related Resources
- Troubleshooting Guide - Detailed problem-solving
- Best Practices - Recommended patterns
- Conventions - Naming and organization standards
- Glossary - Term definitions