devalade / crudify
Generate full CRUD with Livewire v4 components in Laravel
Requires
- php: ^8.2
- laravel/framework: ^11.0|^12.0|^13.0
- livewire/livewire: ^4.0
- symfony/yaml: ^6.0|^7.0|^8.0
Requires (Dev)
- laravel/pint: ^1.29
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.0
README
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.
Installation
composer require devalade/crudify --dev
Quick Start
CLI
php 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-delete
Volt 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.
Classic Livewire
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" \
--livewire
YAML
php artisan crudify:generate --file=post.yaml
post.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: true
Then run:
php artisan migrate
Visit /{resource} (e.g. /posts).
Field Syntax
CLI Format
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 |
Available Types
string, text, integer, bigint, float, double, decimal, boolean, date, datetime, timestamp, time, json, uuid, email, foreign, image, file
Modifiers
nullable— allows NULL valuesunique— adds unique constraintindex— adds database indexdefault:value— sets default valueforeign:table— creates foreign key constraintmultiple— enables multiple file uploads (forimageandfiletypes)
File Uploads
Crudify supports single and multiple file/image uploads out of the box — for both Volt SFCs and classic Livewire pages.
Single Upload
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
Multiple Uploads
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
Relationships
Define Eloquent relationships in your model with a simple syntax.
CLI
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"
YAML
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: Topics
Supported Types
belongsTo— 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
Relationship Display API
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: Topics
Behavior:
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
belongsToMany Example
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: Topics
Run:
php artisan crudify:generate --file=post.yaml
Generated 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
Generated Files
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
Livewire 4 Compatible
All generated components use Livewire 4 syntax:
#[Validate]attributes on properties (fixesMissingRulesException)#[Layout]and#[Title]attributesWithFileUploadstrait for file handlingwire:confirmfor delete confirmations
UI Framework
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']) @fluxScripts
Bootstrap setup files with:
php artisan crudify:setup
This 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 --volt
crudify:install:
- installs
livewire/flux - installs
livewire/voltwhen--voltused - installs
tailwindcssand@tailwindcss/vitevia npm whenpackage.jsonexists - runs
crudify:setup
Command Options
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 files
Examples
Generate 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" \
--livewire
Generate only model and migration:
php artisan crudify:generate Post --fields="title:string" --only=model|migration
Skip controllers (Livewire-only):
php artisan crudify:generate Post --fields="title:string" --skip=controller
Preview changes:
php artisan crudify:generate Post --fields="title:string" --dry-run
Customizing Stubs
Publish stubs to your application:
php artisan crudify:stubs
Then edit files in stubs/crudify/. The package will use your custom stubs on the next generation.
Requirements
- PHP ^8.2
- Laravel ^11.0, ^12.0 or ^13.0
- Livewire ^4.0
Testing
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 style
License
MIT