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 migrate

Then 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>
@endcan

Integrating 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

More Posts