brackets/craftable
Craftable is a Laravel admin panel and CRUD generator for building customizable backends quickly. It includes authentication, roles and permissions, media management, and ready-made UI components to speed up admin development.
Craftable is not a drop-in library you use in an existing app — it is an administration scaffold. The intended entry point is a fresh Laravel 8 application (or the brackets/craftable-project skeleton), because installation publishes auth, layouts, routes, and a Vue/Inertia front end that you are expected to own and edit.
Minimal steps:
composer require brackets/craftable
php artisan craftable:install # publishes config, assets, migrations, seeds admin user
php artisan migrate
npm install && npm run dev # or watch
php artisan serve
Log in at /admin with the seeded credentials (check the installer output — it prints them). The three places to look first:
routes/admin.php — every admin route, including generated CRUD routes, is registered here.resources/js/admin/ — Inertia pages and Vue form/table components; this is where the UI actually lives.app/Http/Controllers/Admin/ — generated controllers extending Craftable's base CRUD controller.The first real use case is generating an entity:
php artisan admin:generate
Walk the interactive prompts (model name, fields and their types, whether the entity is translatable, whether it has media). The generator emits a migration, model, form request, admin controller, Vue index/create/edit pages, routes, and permission records. Run php artisan migrate, assign the new permissions to a role in the built-in Roles & Permissions screen, and the CRUD is live.
Generator-first, then hand-edit. Treat admin:generate as a scaffolding event, not an ongoing source of truth. Commit the generated files, then customize freely. Regenerating the same entity will overwrite your edits, so most teams only re-run it for brand-new entities.
Controller pattern. Generated controllers extend the package's base CRUD controller and declare an $indexView, $createView, $editView, and a model class. Index actions receive sorting and search query parameters from the Vue table, so custom filters are added by extending the query in the controller and passing filter options back as Inertia props.
Vue page pattern. Each generated entity has an index page (table, search, sort, bulk delete, pagination) and a form page composed of field components (text, textarea, richtext, select, checkbox, date, media, etc.). To change behavior, edit the Vue page or the field component in resources/js/admin — not the PHP side. Form submissions go through Inertia to the controller's store/update.
Translatable content. If the entity is flagged translatable, the generator uses a translation table or JSON column plus a locale switcher. Forms render one tab per configured locale. Non-translatable fields sit outside the tabs, and validation rules must be keyed by locale in the form request.
Media and files. Craftable leans on Spatie MediaLibrary. Models must implement HasMedia and register collections; the media field component expects that collection name. Thumbnails/conversions are configured in the model's registerMediaCollections/registerMediaConversions, not in the admin UI.
Permissions and menu. Every generated entity registers index/create/update/delete abilities. Roles and permissions are managed inside the admin itself; the menu is config-driven (order, icon, permission gate), so hiding a section for non-admins is a config change plus a permission assignment. Super-admin bypasses checks.
Integration tips. Publish config and views (vendor:publish --provider=...) before overriding, so your customizations survive a composer update. For bespoke admin screens that the generator can't express, build a normal Laravel controller + Inertia page in the same namespace and register the route in routes/admin.php so it inherits auth and layout.
laravel/framework and related packages, and plan to fork or migrate rather than composer update blindly.php artisan migrate; the resulting 500 is a common first-run confusion.npm run dev (or build), clear config:cache and route:cache, and check for a stale Inertia manifest. After adding routes, re-run route:clear.resources/js/admin for adding a custom input type.routes/web.php and leave routes/admin.php for the panel.How can I help you explore Laravel packages today?