Reference

Frequently Asked Questions

Common questions and answers about Nuxt Crouton
Query Examples: For complete 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 when useMetadata: true (default)
  • teamId, userId - Generated when useTeamUtility: 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:

  1. Keep custom components separate - Place them in subdirectories like components/custom/
  2. Use slots for overrides - Override specific fields/columns via slots instead of editing generated files
  3. 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:

  1. Collection name matches between query and mutation
  2. 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
Examples: See Mutation Composables API for complete usage patterns.

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.

See: Customization Overview


TypeScript & Development

Q: Why am I getting "Cannot find module" errors after generation?

A: TypeScript server needs to be restarted:

In VS Code:

  1. Press Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows)
  2. Type "Restart TS Server"
  3. 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


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:

  1. Schema is passed to form: :schema="schema"
  2. Field names match schema keys
  3. State is reactive (ref() or reactive())
<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:

  1. Implement pagination - See Querying with Pagination
  2. Use server-side filtering - Filter in your database, not the frontend
  3. 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:

  1. Extend the i18n layer:
// nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    '@friendlyinternet/nuxt-crouton',
    '@friendlyinternet/nuxt-crouton-i18n'
  ]
})
  1. Mark fields as translatable:
// crouton.config.js
export default {
  translations: {
    collections: {
      products: ['name', 'description']
    }
  }
}
  1. 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:

  1. Check Troubleshooting Guide for detailed solutions
  2. Search GitHub Issues for similar problems
  3. Ask in GitHub Discussions for general questions
  4. Create an issue with:
    • Nuxt Crouton version
    • Nuxt version
    • Error messages
    • Minimal reproduction steps