| Install | |
|---|---|
composer require necro304/crud-inertia-shadcn |
|
| Latest Version: | 0.0.1 |
| PHP: | ^8.4|^8.3 |
A powerful Laravel package that generates complete, production-ready CRUD modules with a modern tech stack: Vue 3, Inertia.js, Shadcn-vue, and Tailwind CSS 4. Generate models, controllers, form requests, API resources, Vue components, and database migrations with a single Artisan command.
✨ Complete CRUD Generation
🎨 Modern UI Components
🔍 Advanced Features
📦 Best Practices
Install the package via Composer:
composer require necro304/crud-inertia-shadcn
The package will automatically register its service provider.
php artisan vendor:publish --tag="crud-generator-config"
This will create a config/crud-generator.php file where you can customize:
Generate a complete CRUD module with a single command:
php artisan make:crud Product name:string description:text price:decimal:nullable stock:integer
This command generates:
app/Models/Product.php - Eloquent model with casts, relationships, soft deletes, and auditingapp/Http/Controllers/ProductController.php - RESTful controller with index, create, store, show, edit, update, destroyapp/Http/Requests/Product/StoreProductRequest.php - Validation rules for creating productsapp/Http/Requests/Product/UpdateProductRequest.php - Validation rules for updating productsapp/Http/Resources/ProductResource.php - API resource for JSON transformationdatabase/migrations/xxxx_xx_xx_create_products_table.php - Database migrationresources/js/pages/Products/Index.vue - List view with DataTable, filtering, search, and paginationresources/js/pages/Products/Create.vue - Creation formresources/js/pages/Products/Edit.vue - Edit form with pre-filled dataresources/js/pages/Products/Show.vue - Detail viewresources/js/pages/Products/components/ProductForm.vue - Reusable form componentDefine fields using the format: name:type[:modifier[:modifier]]
Supported Field Types:
string - VARCHAR(255)text - TEXT columninteger - INTEGER columndecimal - DECIMAL(8,2) columnboolean - BOOLEAN columndate - DATE columndatetime - DATETIME columntimestamp - TIMESTAMP columnjson - JSON columnSupported Modifiers:
nullable - Allow NULL valuesunique - Add unique constraintindex - Add database indexExamples:
# String field, nullable
php artisan make:crud Post title:string:nullable
# Decimal with nullable
php artisan make:crud Invoice total:decimal:nullable
# Multiple modifiers
php artisan make:crud User email:string:unique:index
| Flag | Description |
|---|---|
--no-soft-deletes |
Disable soft deletes in the model |
--no-auditing |
Disable model auditing |
--no-views |
Skip Vue component generation |
--table=custom_name |
Specify a custom table name |
--force |
Overwrite existing files without confirmation |
Examples:
# Generate without soft deletes
php artisan make:crud Product name:string --no-soft-deletes
# Custom table name
php artisan make:crud UserProfile name:string --table=user_profiles
# Skip frontend generation (API only)
php artisan make:crud Category name:string --no-views
# Overwrite existing files
php artisan make:crud Product name:string --force
This package includes AI assistant guidelines to help tools like Claude Code, GitHub Copilot, or Cursor AI understand how to work with the generated code.
Publish the AI guidelines to your project's .ai/guidelines/ directory:
php artisan crud-generator:publish-guidelines
This creates .ai/guidelines/crud-inertia-shadcn.md with:
Benefits:
Options:
# Overwrite existing guidelines
php artisan crud-generator:publish-guidelines --force
The guidelines file can be customized to match your specific project needs and coding standards.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use OwenIt\Auditing\Contracts\Auditable;
class Product extends Model implements Auditable
{
use SoftDeletes;
use \OwenIt\Auditing\Auditable;
protected $fillable = ['name', 'description', 'price', 'stock'];
protected function casts(): array
{
return [
'price' => 'decimal:2',
'stock' => 'integer',
];
}
}
namespace App\Http\Controllers;
use App\Models\Product;
use App\Http\Requests\Product\StoreProductRequest;
use App\Http\Resources\ProductResource;
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;
use Inertia\Inertia;
class ProductController extends Controller
{
public function index()
{
$products = QueryBuilder::for(Product::class)
->allowedFilters([
AllowedFilter::callback('search', function ($query, $value) {
$query->where('name', 'like', "%{$value}%")
->orWhere('description', 'like', "%{$value}%");
}),
AllowedFilter::partial('name'),
])
->allowedSorts(['name', 'price', 'created_at'])
->defaultSort('-created_at')
->paginate(15)
->withQueryString();
return Inertia::render('Products/Index', [
'products' => ProductResource::collection($products),
]);
}
// ... other CRUD methods
}
<script setup lang="ts">
import { router } from '@inertiajs/vue3'
import { DataTable } from '@/components/ui/data-table'
import { useCrudColumns } from '@/composables/useCrudColumns'
import { useDebounceFn } from '@vueuse/core'
const props = defineProps<{
products: PaginatedResponse<Product>
}>()
const { columns } = useCrudColumns<Product>([
{ key: 'name', label: 'Name', sortable: true },
{ key: 'price', label: 'Price', sortable: true },
{ key: 'stock', label: 'Stock' },
])
const handleSearch = useDebounceFn((value: string) => {
router.visit(route('products.index'), {
data: { search: value },
preserveState: true,
})
}, 300)
</script>
<template>
<DataTable
:columns="columns"
:data="products.data"
:pagination="products"
@search="handleSearch"
/>
</template>
After generating a CRUD, you can manually add relationships to the model:
// app/Models/Product.php
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function reviews(): HasMany
{
return $this->hasMany(Review::class);
}
Then update the controller to eager load relationships:
// app/Http/Controllers/ProductController.php
$products = QueryBuilder::for(Product::class)
->with(['category', 'reviews']) // Eager load relationships
->allowedFilters([...])
// ...
For models with file upload fields (e.g., images, documents):
php artisan make:crud Company name:string logo:string:nullable
Then update the controller to handle file uploads:
// app/Http/Controllers/CompanyController.php
public function store(StoreCompanyRequest $request)
{
$data = $request->validated();
if ($request->hasFile('logo')) {
$data['logo'] = $request->file('logo')->store('companies/logos', 'public');
}
Company::create($data);
return redirect()->route('companies.index');
}
Edit the generated Form Request classes to add custom validation messages:
// app/Http/Requests/Product/StoreProductRequest.php
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'price' => ['required', 'numeric', 'min:0'],
'stock' => ['required', 'integer', 'min:0'],
];
}
public function messages(): array
{
return [
'name.required' => 'The product name is required.',
'price.min' => 'The price must be at least 0.',
'stock.min' => 'Stock cannot be negative.',
];
}
The generated Vue components use a modern, production-ready stack:
<script setup> syntaxuseDebounceFn for search)Run the package tests:
# Run all tests
composer test
# Run tests with coverage
composer test-coverage
# Run PHPStan static analysis
composer analyse
# Fix code style issues
composer format
Generated CRUD modules should have corresponding tests:
// tests/Feature/ProductControllerTest.php
use App\Models\Product;
it('can list products', function () {
Product::factory()->count(3)->create();
$response = $this->get(route('products.index'));
$response->assertSuccessful();
});
it('can create a product', function () {
$data = [
'name' => 'Test Product',
'price' => 99.99,
'stock' => 10,
];
$response = $this->post(route('products.store'), $data);
$response->assertRedirect(route('products.index'));
$this->assertDatabaseHas('products', ['name' => 'Test Product']);
});
Please see CHANGELOG for more information on recent changes.
Contributions are welcome! Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
Built with inspiration from the Laravel ecosystem and modern frontend practices.
The MIT License (MIT). Please see License File for more information.