The @fyit/crouton-cli package provides a powerful CLI tool for generating complete CRUD collections. This reference covers all available commands, options, and workflows.
npm install -g @fyit/crouton-cli
After global installation, both crouton and crouton-generate commands are available everywhere:
crouton --help
# or
crouton-generate --help
crouton command is an alias for crouton-generate. Both work identically.# Use directly without installation
npx @fyit/crouton-cli <command>
# Or add to project devDependencies
pnpm add -D @fyit/crouton-cli
npx crouton-generate <command>
The CLI provides the following commands:
| Command | Purpose | Usage |
|---|---|---|
generate | Generate collections | Single collection or from config file |
init | Scaffold a full app | End-to-end: scaffold, generate, doctor, summary |
config | Use config file | Alternative syntax for config-based generation |
add | Add modules/features | Add Crouton modules like auth, editor, events |
rollback | Remove collections | Single, bulk, or interactive removal |
doctor | Validate app | Checks deps, wrangler, stubs, schema wiring |
scaffold-app | Create app skeleton | Generates boilerplate files for a new app |
seed-translations | Seed i18n data | Seed translations from JSON locale files to DB |
db-pull | Pull remote DB | Pull remote D1 database into local dev |
deploy-setup | Setup deployment | Interactive Cloudflare Pages deployment setup |
deploy-check | Check deploy readiness | Validate wrangler config, CI workflow, bindings |
Generate a new CRUD collection with all necessary files.
crouton-generate <layer> <collection> [options]
<layer> - Target layer name (e.g., shop, admin, blog)<collection> - Collection name in plural form (e.g., products, users, posts)productOptions becomes productoptions/ in the file system. Use kebab-case (e.g., product-options) for multi-word collection names.| Option | Type | Default | Description |
|---|---|---|---|
-f, --fields-file <path> | string | - | Path to JSON schema file (required) |
-d, --dialect <type> | pg|sqlite | sqlite | Database dialect |
--auto-relations | boolean | false | Add relation stubs in comments |
--dry-run | boolean | false | Preview without creating files |
--no-translations | boolean | false | Skip translation field generation |
--force | boolean | false | Overwrite existing files |
--no-db | boolean | false | Skip database table creation |
--hierarchy | boolean | false | Enable hierarchy support (parentId, path, depth, order) |
--seed | boolean | false | Generate seed data file with drizzle-seed |
--count <number> | number | 25 | Number of seed records to generate |
--no-auto-merge | boolean | false | Skip automatic merging of generated files with existing ones |
-c, --config <path> | string | - | Use config file instead |
Basic generation:
crouton-generate shop products --fields-file=./schemas/product.json
With options:
crouton-generate admin users \
--fields-file=./schemas/user.json \
--dialect=pg \
--force
Preview changes (dry run):
crouton-generate blog posts \
--fields-file=./schemas/post.json \
--dry-run
Using config file:
crouton-generate --config ./crouton.config.js
With hierarchy support:
crouton-generate content pages \
--fields-file=./schemas/page.json \
--hierarchy
Each generate command creates:
layers/[layer]/collections/[collection]/
├── app/
│ ├── components/
│ │ ├── _Form.vue # CRUD form with validation
│ │ ├── List.vue # Data table/list
│ │ └── RepeaterItem.vue # For repeater fields (if needed)
│ └── composables/
│ └── use[Layer][Collection].ts # Zod schema, columns, defaults (e.g., useShopProducts.ts)
├── server/
│ ├── api/teams/[id]/[collection]/
│ │ ├── index.get.ts # GET all/by IDs
│ │ ├── index.post.ts # CREATE
│ │ ├── [id].patch.ts # UPDATE
│ │ └── [id].delete.ts # DELETE
│ └── database/
│ ├── queries.ts # Query functions
│ ├── schema.ts # Drizzle schema
│ └── seed.ts # Seed data (with --seed flag)
├── types.ts # TypeScript interfaces
└── nuxt.config.ts # Layer configuration
When using the --hierarchy flag (or hierarchy: true in config), additional files and fields are generated for tree/nested data structures:
Additional database fields:
parentId - Reference to parent record (nullable)path - Materialized path for efficient tree queriesdepth - Nesting level (0 for root items)order - Sort order within siblingsAdditional API endpoints:
[id]/move.patch.ts - Move item to new parentreorder.patch.ts - Reorder sibling itemsAdditional queries:
getTreeData() - Fetch hierarchical dataupdatePosition() - Update item positionreorderSiblings() - Reorder items at same levelZod schema includes:
parentId: z.string().nullable().optional()
Default values include:
parentId: null
Generate realistic test data alongside your collections using drizzle-seed + Faker.
CLI usage:
# Generate with seed data (25 records by default)
crouton-generate shop products --fields-file=products.json --seed
# Generate with custom record count
crouton-generate shop products --fields-file=products.json --seed --count=100
Config file usage:
// crouton.config.js
export default {
collections: [
{ name: 'products', fieldsFile: './schemas/products.json', seed: true }, // 25 records
{ name: 'categories', fieldsFile: './schemas/categories.json', seed: { count: 50 } } // custom count
],
seed: {
defaultCount: 25, // default for all collections
defaultTeamId: 'seed-team' // team ID for seeded data
},
// ... other config
}
Running seeds:
After generation, execute the seed file:
# Run directly
npx tsx ./layers/shop/collections/products/server/database/seed.ts
# Or import in your code
import { seedShopProducts } from './layers/shop/collections/products/server/database/seed'
await seedShopProducts({
count: 100,
teamId: 'my-team',
reset: true // optionally clear existing data first
})
Field-to-generator mapping:
The seed generator auto-detects field names and generates appropriate data:
| Field Pattern | Generated Data |
|---|---|
email | f.email() - realistic email addresses |
name, fullName | f.fullName() - person names |
title | f.loremIpsum({ sentencesCount: 1 }) |
description, content | f.loremIpsum({ sentencesCount: 3 }) |
price, amount | f.number({ minValue: 1, maxValue: 1000 }) |
| Foreign keys | Placeholder values with dependency comments |
Scaffold a full Crouton app end-to-end: creates the app skeleton, generates collections from config, runs doctor validation, and prints a summary with next steps.
crouton-generate init <name> [options]
<name> - App name (required)| Option | Type | Default | Description |
|---|---|---|---|
--features <list> | string | - | Comma-separated feature names (e.g., bookings,pages,editor) |
--theme <name> | string | - | Theme to wire into extends (e.g., ko) |
-d, --dialect <type> | string | sqlite | Database dialect (sqlite or pg) |
--no-cf | boolean | false | Skip Cloudflare-specific config (wrangler.toml, CF stubs) |
--dry-run | boolean | false | Preview what will be generated without writing files |
# Create app with default settings
crouton-generate init my-app
# With features and theme
crouton-generate init my-app --features bookings,pages,editor --theme ko
# Preview without writing
crouton-generate init my-app --dry-run
The init command runs a full pipeline:
crouton.config.js (if collections are defined)init, you can customize the generated crouton.config.js and schemas, then re-run crouton-generate config to regenerate collections.Add pre-built features to your existing Nuxt Crouton project.
crouton-generate add <feature> [options]
<feature> - Feature to add (available: auth, i18n, admin, bookings, editor, assets, events, flow, email, maps, ai, devtools)| Option | Type | Default | Description |
|---|---|---|---|
--dry-run | boolean | false | Preview what will be generated |
--force | boolean | false | Overwrite existing files |
Add the crouton-events layer for audit trail tracking. This creates a complete event tracking system that automatically logs all collection mutations (create, update, delete).
# Add events layer
crouton-generate add events
# Preview what will be created
crouton-generate add events --dry-run
# Overwrite existing files
crouton-generate add events --force
The add events command creates:
layers/crouton-events/
├── nuxt.config.ts # Layer configuration
├── types.ts # TypeScript interfaces
└── server/
├── database/
│ ├── schema.ts # Drizzle schema for events table
│ └── queries.ts # Query functions (getAll, create, etc.)
└── api/teams/[id]/crouton-collection-events/
├── index.get.ts # GET all events
├── index.post.ts # CREATE event
├── [eventId].patch.ts # UPDATE event
└── [eventId].delete.ts # DELETE event
The command also updates:
nuxt.config.ts - Adds './layers/crouton-events' to extends arrayserver/database/schema/index.ts - Adds schema export# 1. Run database migration
pnpm drizzle-kit generate
pnpm drizzle-kit migrate
# 2. Install the events tracking package (for auto-tracking)
pnpm add @fyit/crouton-events
# 3. Add to nuxt.config.ts extends
# '@fyit/crouton-events'
add events command creates the server-side storage layer. To enable automatic event tracking for all collection mutations, also install @fyit/crouton-events package. See Events Package for full documentation.Alternative syntax for generating collections using a configuration file.
crouton-generate config [configPath] [options]
[configPath] - Path to config file (auto-detected if not specified)crouton.config.tscrouton.config.jscrouton.config.mjscrouton.config.cjs| Option | Type | Description |
|---|---|---|
--only <name> | string | Generate only a specific collection from the config |
# Auto-detect config file (searches for crouton.config.js/.mjs/.cjs/.ts)
crouton-generate config
# Use specific config file
crouton-generate config ./configs/production.config.mjs
# Generate only a single collection from config
crouton-generate config --only products
# Combine config path with --only flag
crouton-generate config ./crouton.config.js --only pages
# Alternative: Use --config flag with generate command
crouton-generate --config ./crouton.config.js
See Configuration File section below for complete details.
Remove generated collections with various strategies.
Remove a specific collection:
crouton-generate rollback <layer> <collection> [options]
Arguments:
<layer> - Layer name containing the collection<collection> - Collection name to removeOptions:
| Option | Description |
|---|---|
--dry-run | Preview what will be removed |
--keep-files | Only clean configs, keep generated files |
--force | Force removal without warnings |
Example:
# Preview removal
crouton-generate rollback shop products --dry-run
# Remove with confirmation
crouton-generate rollback shop products
# Force remove without prompts
crouton-generate rollback shop products --force
Remove entire layers or multiple collections:
crouton-generate rollback-bulk [options]
Options:
| Option | Description |
|---|---|
--layer <name> | Remove entire layer with all collections |
--config <path> | Remove collections defined in config file |
--dry-run | Preview what will be removed |
--keep-files | Only clean configs, keep files |
--force | Force removal without warnings |
Examples:
# Remove entire layer
crouton-generate rollback-bulk --layer=shop
# Preview layer removal
crouton-generate rollback-bulk --layer=shop --dry-run
# Remove collections from config file
crouton-generate rollback-bulk --config=./crouton.config.js
# Force bulk removal
crouton-generate rollback-bulk --layer=shop --force
Use an interactive UI to select what to remove:
crouton-generate rollback-interactive [options]
Options:
| Option | Description |
|---|---|
--dry-run | Preview what will be removed |
--keep-files | Only clean configs, keep files |
Interactive Flow:
$ crouton-generate rollback-interactive
═══════════════════════════════════════════════════════════
INTERACTIVE ROLLBACK
═══════════════════════════════════════════════════════════
Found 3 layers:
• shop (5 collections)
• blog (3 collections)
• admin (2 collections)
? What would you like to rollback?
❯ Entire layer (all collections)
Specific collections
Cancel
? Select layer:
❯ shop (5 collections)
blog (3 collections)
admin (2 collections)
? Are you sure you want to remove layer "shop"? (Y/n)
--dry-run first to preview changes. The rollback command removes:layers/[layer]/collections/[collection]/server/database/schema/index.tsapp.config.tsnuxt.config.ts (for bulk operations)Check and install required Nuxt modules (mainly for development).
crouton-generate install
This command checks for and installs:
@fyit/crouton (core package)The configuration file provides a declarative way to define all generation settings.
// crouton.config.js
export default {
// Path to JSON schema files directory
schemaPath: './schemas/',
// Database dialect
dialect: 'sqlite', // or 'pg'
// Target layers and collections
targets: [
{
layer: 'shop',
collections: [
// Simple string for basic collections
'products',
// Or object with per-collection options
{
name: 'orders',
fieldsFile: './schemas/order.json',
seed: true,
hierarchy: false
}
]
}
],
// Seed configuration (optional)
seed: {
defaultCount: 25,
defaultTeamId: 'seed-team'
},
// Generation flags
flags: {}
}
Type: string
Path to your JSON schema file(s). Can be:
'./product-schema.json''./schemas/' (uses convention [collection]-schema.json)export default {
schemaPath: './schemas/', // Looks for products-schema.json, etc.
targets: [
{
layer: 'shop',
collections: ['products', 'categories'] // Uses products-schema.json, categories-schema.json
}
]
}
Type: 'pg' | 'sqlite'
Default: 'sqlite'
Database dialect for generated schemas and queries.
export default {
dialect: 'pg', // PostgreSQL
// Or
dialect: 'sqlite' // SQLite (default)
}
Type: Array<{ layer: string, collections: (string | CollectionConfig)[] }>
Defines which collections to generate in which layers. Collections can be:
schemaPath/[name]-schema.json)export default {
targets: [
{
layer: 'shop',
collections: [
'products', // Simple: uses schemas/products-schema.json
'categories', // Simple: uses schemas/categories-schema.json
{ // With options
name: 'orders',
fieldsFile: './schemas/order.json',
seed: { count: 50 },
hierarchy: true
}
]
},
{
layer: 'blog',
collections: [
{ name: 'posts', seed: true },
{ name: 'authors', seed: { count: 10 } }
]
}
]
}
Per-collection options:
| Option | Type | Description |
|---|---|---|
name | string | Collection name (required) |
fieldsFile | string | Path to schema file (overrides schemaPath) |
seed | boolean | { count: number } | Generate seed data |
hierarchy | boolean | Enable tree/hierarchy support |
Type: object
Generation behavior flags.
teamId and owner fields and uses @fyit/crouton-auth/server for authentication. Do NOT define these fields in your schemas.Type: boolean
Default: true
Automatically add timestamp and audit fields:
createdAt - Timestamp when record was createdupdatedAt - Timestamp when record was last modifiedcreatedBy - User ID who created the recordupdatedBy - User ID who last modified the recordexport default {
flags: {
useMetadata: true // Add timestamps (default)
}
}
useMetadata: true, do NOT define createdAt, updatedAt, or updatedBy in your schemas.Type: boolean
Default: false
Add relation helper comments to generated schemas.
export default {
flags: {
autoRelations: true
}
}
Type: boolean
Default: false
Skip translation field generation.
export default {
flags: {
noTranslations: true // Don't generate translation fields
}
}
Type: boolean
Default: false
Overwrite existing files without prompting.
export default {
flags: {
force: true // Overwrite files
}
}
Type: boolean
Default: false
Skip database table creation (generate code only).
export default {
flags: {
noDb: true // Skip database operations
}
}
Type: boolean
Default: false
Preview what will be generated without creating files.
export default {
flags: {
dryRun: true // Preview only
}
}
// crouton.config.js
export default {
// Schema location
schemaPath: './schemas/',
// Database
dialect: 'sqlite',
// Target layers and collections
targets: [
{
layer: 'shop',
collections: [
{ name: 'products', seed: true },
{ name: 'categories', seed: { count: 10 } },
{ name: 'orders', seed: { count: 100 } }
]
},
{
layer: 'content',
collections: [
{ name: 'pages', hierarchy: true },
{ name: 'posts', seed: true },
'authors' // Simple string also works
]
}
],
// Seed configuration
seed: {
defaultCount: 25,
defaultTeamId: 'seed-team'
},
// Generation flags
flags: {
// Timestamps
useMetadata: true,
// Relations
autoRelations: false,
// Translation fields
noTranslations: false,
// Database
noDb: false,
// Behavior
force: false,
dryRun: false
}
}
# 1. Scaffold a full app (runs scaffold-app → generate → doctor → summary)
crouton-generate init my-app
# 2. Customize the generated schemas and crouton.config.js
# 3. Regenerate collections if needed
crouton-generate config
# 4. Start dev server
cd my-app
pnpm dev
# 1. Create config file
cat > crouton.config.js << 'CONF'
export default {
schemaPath: './schemas/',
dialect: 'sqlite',
targets: [
{
layer: 'shop',
collections: ['products', 'categories', 'orders']
}
],
flags: {
useMetadata: true,
force: false
}
}
CONF
# 2. Create schema files
mkdir -p schemas
# (Create products-schema.json, categories-schema.json, orders-schema.json)
# 3. Generate all at once
crouton-generate config
# 4. Export schemas
echo "export * from '~/layers/shop/collections/products/server/database/schema'" >> server/database/schema/index.ts
echo "export * from '~/layers/shop/collections/categories/server/database/schema'" >> server/database/schema/index.ts
echo "export * from '~/layers/shop/collections/orders/server/database/schema'" >> server/database/schema/index.ts
# Use --dry-run to see what would be generated
crouton-generate shop products \
--fields-file=schemas/product.json \
--dry-run
# Output shows:
# - Files that would be created
# - Directories that would be created
# - Schemas that would be registered
# 1. Preview removal
crouton-generate rollback shop products --dry-run
# 2. Review what will be removed
# 3. Execute removal
crouton-generate rollback shop products
# 4. Remove schema export manually from server/database/schema/index.ts
# Use interactive mode for safety
crouton-generate rollback-interactive
# Select "Entire layer"
# Select the layer to remove
# Confirm removal
The generator incorporates fixes and improvements documented in /docs/extraction-notes.md:
Generated API endpoints include team-based authorization by default:
// Generated: server/api/teams/[id]/products/index.get.ts
import { resolveTeamAndCheckMembership } from '@fyit/crouton-auth/server/utils/team'
export default defineEventHandler(async (event) => {
const { team, user } = await resolveTeamAndCheckMembership(event)
// team is automatically resolved and verified
// All queries automatically scoped to team.id
const products = await getProducts({ teamId: team.id })
return products
})
@fyit/crouton. You don't need to install it separately.All date fields use proper UTC storage and timezone handling:
{
"publishedAt": {
"type": "date"
}
}
Generated code includes:
External references (:users, :teams) trigger automatic connector setup with proper type safety and composables.
Problem: crouton-generate: command not found
Solutions:
# Option 1: Install globally
npm install -g @fyit/crouton-cli
# Option 2: Use npx
npx @fyit/crouton-cli <command>
# Option 3: Add to project and use npx
pnpm add -D @fyit/crouton-cli
npx crouton-generate <command>
Problem: Build fails with duplicate key errors (e.g., userId, teamId)
Cause: You defined auto-generated fields in your schema
Solution: Remove auto-generated fields from schema:
id (always auto-generated)teamId, owner (always auto-generated for team-scoped collections)createdAt, updatedAt, updatedBy (when useMetadata: true)Problem: Error: Config file not found: ./crouton.config.js
Solutions:
# Use correct path
crouton-generate config ./path/to/config.js
# Or use --config flag
crouton-generate --config ./path/to/config.js
# Or ensure default location exists
ls crouton.config.js
Problem: Error: Schema file not found
Solutions:
# Use absolute path
crouton-generate shop products --fields-file=/full/path/to/schema.json
# Or use relative path from project root
crouton-generate shop products --fields-file=./schemas/product.json
# Verify file exists
ls ./schemas/product.json
Problem: Type errors in generated code
Solutions:
# 1. Ensure Nuxt Crouton is installed
pnpm add @fyit/crouton
# 2. Run Nuxt prepare to regenerate types
npx nuxt prepare
# 3. Run typecheck
npx nuxt typecheck
# 4. Restart TypeScript server in your editor
Problem: Some files remain after rollback
Explanation: Rollback only removes generated files, not manual modifications or schema exports.
Manual cleanup needed:
server/database/schema/index.tsProblem: EACCES: permission denied
Solutions:
# Check file permissions
ls -la layers/
# Fix permissions
chmod -R u+w layers/
# Or run with sudo (not recommended)
sudo crouton-generate ...
useMetadata: true for audit trails:prefix for external refsmeta.required, meta.maxLength, etc.crouton.config.jsdryRun before actual generationserver/database/schema/index.tsnpx nuxt typecheck)--dry-run first@fyit/crouton-clinuxt-crouton-collection-generatorcrouton and crouton-generate commands availableinit, add, doctor, scaffold-app, seed-translations, db-pull, deploy-setup, deploy-check