Generate full CRUD scaffolding for Laravel with a single command. Built for Livewire v4 and Laravel 11/12/13.
Crudify creates models, migrations, policies, Volt or Livewire CRUD pages, factories, and seeders — with support for relationships, soft deletes, file uploads, and searchable fields.
composer require devalade/crudify --devphp artisan crudify:generate Post \
--fields="title:string|body:text|is_published:boolean|published_at:datetime" \
--relationships="user:belongsTo:User|category:belongsTo:Category|tags:belongsToMany:Tag" \
--soft-deleteVolt single-file components are generated by default.
This generates SFCs directly in resources/views/pages/posts/:
index.blade.php— list with search, sort, paginationcreate.blade.php— inline validation with#[Validate]edit.blade.php— edit form with file upload supportshow.blade.php— detail view
Routes are auto-discovered and registered by Crudify's service provider.
Generate classic Livewire page classes, Blade views, controllers, form requests, and routes:
php artisan crudify:generate Post \
--fields="title:string|body:text|is_published:boolean" \
--livewirephp artisan crudify:generate --file=post.yamlpost.yaml
model: Post
fields:
title:
type: string
nullable: false
unique: true
slug:
type: string
nullable: false
unique: true
index: true
body:
type: text
nullable: false
is_published:
type: boolean
default: false
published_at:
type: datetime
nullable: true
# Single image upload
featured_image:
type: image
nullable: true
# Multiple file uploads
gallery:
type: image
multiple: true
nullable: true
# Single file upload
attachment:
type: file
nullable: true
relationships:
user:
type: belongsTo
model: User
category:
type: belongsTo
model: Category
tags:
type: belongsToMany
model: Tag
comments:
type: hasMany
model: Comment
searchable:
- title
- body
options:
soft_deletes: true
volt: trueThen run:
php artisan migrateVisit /{resource} (e.g. /posts).
name:type:modifier1:modifier2
Examples:
| Field Definition | Result |
|---|---|
title:string |
string column |
body:text |
text column |
email:string:unique |
string with unique index |
published_at:datetime:nullable |
nullable datetime |
status:string:default:draft |
string with default value |
user_id:foreign:users |
foreignId constrained to users table |
views:integer:index |
integer with index |
photo:image |
string column + file upload input |
documents:file:multiple |
json column + multiple file upload input |
string, text, integer, bigint, float, double, decimal, boolean, date, datetime, timestamp, time, json, uuid, email, foreign, image, file
nullable— allows NULL valuesunique— adds unique constraintindex— adds database indexdefault:value— sets default valueforeign:table— creates foreign key constraintmultiple— enables multiple file uploads (forimageandfiletypes)
Crudify supports single and multiple file/image uploads out of the box — for both Volt SFCs and classic Livewire pages.
php artisan crudify:generate Product \
--fields="name:string|price:decimal|photo:image"Generates:
stringcolumn for the file pathWithFileUploadstrait in Volt components- File input with
accept="image/*" - Automatic file storage to
storage/app/public/ - Old file deletion on edit
php artisan crudify:generate Gallery \
--fields="title:string|photos:image:multiple"Generates:
jsoncolumn for storing multiple paths- Array-cast in the model
- Multiple file input (
<input type="file" multiple>) removePhotosFile()method for selective removal- Gallery preview grid on edit/show views
Define Eloquent relationships in your model with a simple syntax.
php artisan crudify:generate Post \
--fields="title:string|user_id:foreign:users" \
--relationships="user:belongsTo:User|category:belongsTo:Category|tags:belongsToMany:Tag|comments:hasMany:Comment"relationships:
author:
type: belongsTo
model: User
display: email
label: Author
comments:
type: hasMany
model: Comment
profile:
type: hasOne
model: Profile
tags:
type: belongsToMany
model: Tag
display: slug
label: TopicsbelongsTo— generates dropdown in forms, eager-loaded in indexhasMany— generates model method onlyhasOne— generates model method onlybelongsToMany— generates checkbox group in forms, syncs on save
Relationships are automatically:
- Added to the model with proper return types
- Eager-loaded in generated index components
- Validated in generated forms for classic Livewire mode
- Displayed in index tables and show views
- For
belongsToMany, generates pivot migration and missing related model when needed
Use optional relationship metadata when default name field is not right.
CLI
php artisan crudify:generate Post \
--fields="title:string" \
--relationships="author:belongsTo:User:email|tags:belongsToMany:Tag:slug"CLI format:
name:type:model[:display]
YAML
relationships:
author:
type: belongsTo
model: User
display: email
label: Author
tags:
type: belongsToMany
model: Tag
display: slug
label: TopicsBehavior:
displaychooses field used in selects, checkbox labels, index badges, and show pageslabeloverrides section/table/form label shown to end usersbelongsToManyappears in create/edit as checkboxes and in index/show as badges by default
For a tags:belongsToMany:Tag relationship, the generator produces:
YAML:
model: Post
fields:
title: string
body: text
relationships:
tags:
type: belongsToMany
model: Tag
display: slug
label: TopicsRun:
php artisan crudify:generate --file=post.yamlGenerated artifacts in default Volt mode:
app/Models/Post.phpapp/Models/Tag.phpif missingdatabase/migrations/*_create_posts_table.phpdatabase/migrations/*_create_post_tag_table.php- Volt create/edit checkbox UI
- index badges for related tags
selectedTagsIdsstate and sync logic
For a model named Post, Crudify generates by default:
| File | Description |
|---|---|
app/Models/Post.php |
Eloquent model with $fillable, $casts, traits, and relationships |
database/factories/PostFactory.php |
Factory with Faker methods mapped to field types |
database/seeders/PostSeeder.php |
Seeder calling Post::factory()->count(10)->create() |
database/migrations/xxxx_create_posts_table.php |
Migration with all columns and indexes |
app/Policies/PostPolicy.php |
Authorization policy |
resources/views/pages/posts/index.blade.php |
Volt index page with search, sort, pagination |
resources/views/pages/posts/create.blade.php |
Volt create page with inline validation |
resources/views/pages/posts/edit.blade.php |
Volt edit page |
resources/views/pages/posts/show.blade.php |
Volt show page |
Use --livewire to generate classic extras instead:
app/Http/Controllers/PostsController.phpapp/Http/Requests/StorePostRequest.phpapp/Http/Requests/UpdatePostRequest.phpapp/Livewire/Pages/Posts/*.phpresources/views/livewire/pages/posts/*.blade.phproutes/web.php
All generated components use Livewire 4 syntax:
#[Validate]attributes on properties (fixesMissingRulesException)#[Layout]and#[Title]attributesWithFileUploadstrait for file handlingwire:confirmfor delete confirmations
Generated views use Flux UI components with Tailwind CSS. Generated Blade files include flux:* components plus Tailwind utility classes:
<flux:card>
<flux:input wire:model.live="search" />
<flux:table>...</flux:table>
</flux:card>Install Flux in generated app:
composer require livewire/flux
@fluxAppearance
@vite(['resources/css/app.css', 'resources/js/app.js'])
@fluxScriptsBootstrap setup files with:
php artisan crudify:setupThis command:
- creates
resources/css/app.csswith Tailwind + Flux imports - creates
resources/js/app.js - creates or patches common app layouts with
@fluxAppearance,@vite(...),@livewireScripts, and@fluxScripts - patches Vite config to add
@tailwindcss/vitewhen a Vite config file exists
Install and bootstrap everything automatically:
php artisan crudify:install
php artisan crudify:install --voltcrudify:install:
- installs
livewire/flux - installs
livewire/voltwhen--voltused - installs
tailwindcssand@tailwindcss/vitevia npm whenpackage.jsonexists - runs
crudify:setup
php artisan crudify:generate {model}
--fields= # Field definitions, separated by `|` or `;`
--file= # Path to YAML file (overrides --fields)
--relationships= # Relationships, separated by `|` or `;`
--only= # Generate only specific types (`model|migration` etc.)
--skip= # Skip specific types (`controller;policy` etc.)
--soft-delete # Add soft deletes
--searchable= # Comma-separated searchable fields
--volt # Explicitly generate Volt single-file components (default)
--livewire # Generate classic Livewire pages + controllers + requests + routes
--force # Overwrite existing files
--dry-run # Preview without writing filesGenerate with file uploads:
php artisan crudify:generate Product \
--fields="name:string|price:decimal|photo:image"Generate with relationships:
php artisan crudify:generate Post \
--fields="title:string|body:text" \
--relationships="user:belongsTo:User|tags:belongsToMany:Tag"Generate classic Livewire instead of Volt:
php artisan crudify:generate Post \
--fields="title:string|body:text" \
--livewireGenerate only model and migration:
php artisan crudify:generate Post --fields="title:string" --only=model|migrationSkip controllers (Livewire-only):
php artisan crudify:generate Post --fields="title:string" --skip=controllerPreview changes:
php artisan crudify:generate Post --fields="title:string" --dry-runPublish stubs to your application:
php artisan crudify:stubsThen edit files in stubs/crudify/. The package will use your custom stubs on the next generation.
- PHP ^8.2
- Laravel ^11.0, ^12.0 or ^13.0
- Livewire ^4.0
composer test # Run all tests
composer test:unit # Run unit tests only
composer test:feature # Run feature tests only
composer analyse # Run static analysis
composer format # Fix code styleMIT