Laravel Permissions with Spatie — A Practical Guide
Author: Gabriel
Published: 3/5/2026
Managing user roles and permissions in Laravel doesn’t have to be complex. The spatie/laravel-permission package makes it elegant and flexible. This practical guide walks you through installation, setup, and real-world usage patterns — from basic role checks to advanced policy integration.
Role-based access control (RBAC) is one of those things every application eventually needs. Laravel gives you gates and policies out of the box, but as your app grows, you need something more flexible. That’s where spatie/laravel-permission comes in.
Installation
composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrateThen add the HasRoles trait to your User model:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
}Creating Roles and Permissions
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
Permission::create(['name' => 'edit posts']);
Permission::create(['name' => 'delete posts']);
Permission::create(['name' => 'publish posts']);
$editor = Role::create(['name' => 'editor']);
$editor->givePermissionTo(['edit posts', 'publish posts']);
$admin = Role::create(['name' => 'admin']);
$admin->givePermissionTo(Permission::all());Assigning Roles to Users
$user->assignRole('editor');
$user->assignRole(['editor', 'writer']);
$user->removeRole('editor');
$user->syncRoles(['admin']);Checking Roles and Permissions
$user->hasRole('admin');
$user->hasAnyRole(['editor', 'admin']);
$user->can('edit posts');
$user->hasPermissionTo('delete posts');
$user->hasAnyPermission(['edit posts', 'publish posts']);Protecting Routes with Middleware
Route::middleware(['role:admin'])->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});
Route::middleware(['permission:edit posts'])->group(function () {
Route::put('/posts/{post}', [PostController::class, 'update']);
});
Route::middleware(['role:admin|editor'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});Using in Blade Templates
@role('admin')
<a href="/admin">Admin Panel</a>
@endrole
@hasanyrole('admin|editor')
<button>Edit Post</button>
@endhasanyrole
@can('delete posts')
<button class="danger">Delete</button>
@endcanIntegrating with Laravel Policies
class PostPolicy
{
public function update(User $user, Post $post): bool
{
if ($user->hasRole('admin')) {
return true;
}
return $user->hasPermissionTo('edit posts') && $user->id === $post->user_id;
}
}Performance: Caching
Spatie caches roles and permissions automatically. When you update roles programmatically, clear the cache:
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();Final Thoughts
spatie/laravel-permission is one of those packages that earns its place in almost every Laravel project. It’s well-maintained, thoroughly documented, and flexible enough to handle anything from simple role checks to complex multi-guard permission systems. Start simple, then expand as your application grows.
Tags:
LaravelSpatie