sebastienheyd/boilerplate
Laravel Boilerplate is a ready-to-use admin panel package with authentication, users, roles and permissions, menus, settings, and a CRUD generator. It helps you build secure back offices for Laravel applications quickly and consistently.
What it actually gives you: a ready-made AdminLTE 3 admin area — layout, login, users/roles/permissions screens, menu manager and a set of Blade form/layout components — so you spend your time on domain screens instead of shelling.
Install (5 minutes):
composer require sebastienheyd/boilerplate
php artisan boilerplate:install
The installer is the whole onboarding: it publishes config, assets and views, runs the package migrations, seeds roles/permissions and creates a super-admin user. Check the console output — it prints the generated credentials and the URL. Then php artisan list boilerplate shows the full set of commands available in your installed version (install, update, plus user/role helpers) — use that rather than copy-pasting commands from blog posts, because names have shifted between releases.
Where to look first, in this order:
config/boilerplate.php — route prefix (defaults to admin), guard/provider, theme/navbar options, menu and asset registration hooks. This file is your control panel.vendor/sebastienheyd/boilerplate/src/) — the user/role CRUD screens are the reference implementation for your CRUD screens. Copy their structure, not their code.resources/views/vendor/boilerplate/ after publishing — the layout and component templates you'll be extending and occasionally overriding.Boilerplate facade — the runtime API for menus and assets.First use case: log in at /admin as the seeded super-admin, create a role, attach a couple of permissions, create a second user, then add one custom page that extends boilerplate::layout.index and a matching menu entry. That single loop exercises 90% of what you'll do daily.
The page pattern. A controller returns a view that extends the package layout:
return view('reports.index');
@extends('boilerplate::layout.index', ['title' => 'Reports', 'subtitle' => 'Monthly'])
@section('content')
<x-boilerplate::card title="Summary">
...
</x-boilerplate::card>
@endsection
Sections are title, subtitle, content; push page-specific CSS/JS with @push('css') / @push('js'). Every page you build is just a view registered somewhere in the admin route group.
Menu registration belongs in a service provider, not in the config array, once you have more than two entries:
Boilerplate::menu()
->add('Reports', 'admin.reports.index', 'fas fa-chart-bar')
->role('admin');
Register in a dedicated AdminServiceProvider so menu construction is greppable and testable. Scope entries with ->role() / ->permission() — hiding a menu item is UX, the route middleware is the actual security boundary, so set both.
CRUD pattern. Build a resource controller, validate in a FormRequest, and render forms with the package components (x-boilerplate::input, select, checkbox, textarea, date, button). They already carry AdminLTE markup, error state and old-input repopulation — hand-writing <input class="form-control"> is how the admin area slowly drifts out of visual consistency. Use the shipped users/roles controllers as the template for index-with-pagination, create/edit, and flash-message-after-redirect.
Access control. The package layers on Spatie permissions. Protect routes with the role: / permission: middleware aliases, and for record-level rules use Laravel policies as normal — the admin area doesn't get in the way. Seed permissions in your own seeder and re-run it in CI so tests and fresh installs agree on the permission set.
Assets and plugins. Register vendor CSS/JS through Boilerplate::asset() or the plugins config key rather than editing the layout — otherwise your customizations vanish on the next boilerplate:update. For genuinely custom styling, publish the views, override the specific template, and keep the diff small.
Customization workflow that survives upgrades: publish → override the minimum number of views → keep everything else referenced from vendor → re-publish deliberately after each package upgrade and diff. Treat published files as a fork you own.
composer update, run boilerplate:update to refresh published assets/views, then re-apply your overrides from version control. Skipping this is the most common cause of "works locally, broken after deploy" with stale JS against new markup.php artisan permission:cache-reset, or cache:forget spatie.permission.cache on older versions). Symptom: a user "has" a permission in the DB but gets 403./login routes, competing layouts and conflicting auth middleware assumptions. Decide up front whether the package owns admin login or your app does; if the app does, verify the guard in config/boilerplate.php points at your user provider.App\Models\User. The install adds HasRoles and related traits to your model. If you have your own user model, table or guard, resolve that before running migrations — retrofitting later means re-seeding role assignments./admin afterwards breaks every hardcoded URL, menu route name and bookmark. Set it in config on day one and always use route names, never string URLs.config/boilerplate.php, menu definitions or component views: php artisan config:clear && php artisan view:clear. Menu edits that "don't show up" are almost always cached config.addBefore/addAfter and keyed entries, use keys; otherwise guard registration with a flag.src/View/Components/ — that's faster than guessing, and cheaper than reading the whole layout.php artisan route:list | grep admin for routing, @dump($errors) inside the form component for validation, browser network tab for 403s that are actually middleware (HTML redirect) rather than your controller (JSON/500).RefreshDatabase plus your roles/permissions seeder, then actingAs($admin); assert 403 for a user without the permission — that test is the one that catches a middleware accidentally dropped from a route group.plugins array. Anything outside those four is vendor code you'll be patching on every upgrade — resist it.How can I help you explore Laravel packages today?