Skip to main content

Upgrade Essentials

All upgrades of this package should follow these steps:
1

Update Composer

Update your composer.json to specify the new major version:
"spatie/laravel-permission": "^7.0"
Then run:
composer update spatie/laravel-permission
2

Update Migrations

Compare the migration file stubs in the new version against migrations you’ve already run. If necessary, create a new migration by hand to apply database changes.
3

Update Config File

Incorporate any changes to the permission.php config file:
  1. Backup your existing config
  2. Re-publish from the package
  3. Re-apply your customizations
php artisan vendor:publish --tag=permission-config --force
4

Update Custom Models

If you’ve extended package models into your app, compare old and new models and apply relevant updates.
5

Update Custom Methods

If you’ve overridden any methods from package traits, compare old and new traits and apply updates.
6

Check Contracts

If you’ve implemented package contracts in any models, verify method signatures match.
7

Review Changelog

Review the Changelog for all changes.

Upgrading from v6 to v7

Version 7 modernizes the codebase while keeping the upgrade path relatively easy. Most changes are internal improvements.

Requirements

  • PHP: 8.4 or higher
  • Laravel: 12 or higher
  • Test Suite: Now uses Pest 3.0

Breaking Changes

All event classes now have an Event suffix for better clarity:
v6 Classv7 Class
PermissionAttachedPermissionAttachedEvent
PermissionDetachedPermissionDetachedEvent
RoleAttachedRoleAttachedEvent
RoleDetachedRoleDetachedEvent
Action Required: Update your event listeners:
// Before
Event::listen(PermissionAttached::class, function ($event) {
    // ...
});

// After
Event::listen(PermissionAttachedEvent::class, function ($event) {
    // ...
});
All command classes now have a Command suffix:
v6 Classv7 Class
CacheResetCacheResetCommand
CreateRoleCreateRoleCommand
CreatePermissionCreatePermissionCommand
ShowShowCommand
UpgradeForTeamsUpgradeForTeamsCommand
AssignRoleAssignRoleCommand
The artisan command signatures remain unchanged, so your scripts and code that call them via artisan continue to work.
The service provider now extends PackageServiceProvider from spatie/laravel-package-tools.Lumen Support Removed: Version 7 no longer supports Lumen. Continue using v6 if you need Lumen.
  • PermissionRegistrar::clearClassPermissions() has been removed
  • Use clearPermissionsCollection() instead
// Before (deprecated in v6, removed in v7)
$registrar->clearClassPermissions();

// After
$registrar->clearPermissionsCollection();
Return types and parameter types have been added throughout. If you’ve extended classes or traits, update your method signatures:HasPermissions trait:
public function givePermissionTo(...$permissions): static
public function syncPermissions(...$permissions): static
public function revokePermissionTo(...$permissions): static
HasRoles trait:
public function assignRole(...$roles): static
public function removeRole(...$roles): static
public function syncRoles(...$roles): static
PermissionRegistrar:
public function setPermissionClass(string $class): static
public function setRoleClass(string $class): static
public function forgetCachedPermissions(): bool
The __construct(Model $record) method has been removed from the Spatie\Permission\Contracts\Wildcard interface.If you implement this contract, remove the constructor from interface requirements (your concrete class should still accept a Model in its constructor).

Code Modernization

v7 includes internal code modernization that shouldn’t affect most users:
  • Constructor promotion in WildcardPermission
  • Modern PHP syntax throughout (instanceof, ::class, str_contains)
  • Improved type safety
  • Better use of imports

Upgrading from v5 to v6

Version 6 has a few important breaking changes, particularly around ID handling for UUID/ULID support.

Breaking Changes

Due to improved UUID/ULID/GUID support, methods accepting Permission or Role id must receive integers, not numeric strings.The Problem:
// This will fail - '123' is treated as a permission NAME
$user->givePermissionTo('123');
The Solution: Convert string IDs to integers, especially when receiving from HTML forms:
// Convert array of permission IDs from strings to integers
$permissionIds = collect($validated['permission'])
    ->map(fn($val) => (int)$val);

$role->syncPermissions($permissionIds);
This primarily affects UI pages where HTML form data is received as strings.
If you’ve overridden getPermissionClass() or getRoleClass() methods:
  • These methods now return strings, not instances
  • Use :: syntax instead of -> when accessing the model
// Before
$this->getPermissionClass()->where(...)

// After  
$this->permissionClass::where(...)
Migrations have been updated to Laravel 8+ anonymous class syntax.If you see this error:
Error: Access to undeclared static property Spatie\Permission\PermissionRegistrar::$pivotPermission
Your migration file needs upgrading:
1

Backup your migration

cp database/migrations/*_create_permission_tables.php backup/
2

Re-publish the migration

php artisan vendor:publish --tag=permission-migrations --force
3

Re-apply customizations

If you had UUID support or other customizations, re-apply them to the new migration.
The middleware namespace changed from plural to singular:
// Before
\Spatie\Permission\Middlewares\RoleMiddleware::class

// After
\Spatie\Permission\Middleware\RoleMiddleware::class
Update in app/Http/Kernel.php (Laravel 10 and below):
protected $middlewareAliases = [
    'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
    'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
    'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
];
The RoleOrPermissionMiddleware now uses canAny() for checking abilities, which includes all abilities registered by your application (not just this package’s permissions).This may grant access to abilities like “Super Admin” that previously would have failed.
If your tests manually register permissions, remove calls to registerPermissions():
// DELETE this from your tests
app()[\Spatie\Permission\PermissionRegistrar::class]->registerPermissions();

// Keep cache clearing (still needed)
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

New Features in v6

  • Full UUID/ULID/GUID support
  • @haspermission Blade directive
  • withoutRole and withoutPermission query scopes
  • Guard name included in exceptions
  • BackedEnum support for roles and permissions
  • Improved Laravel Octane support
  • Performance improvements for wildcard permissions

Upgrading from v4 to v5

Follow the “Upgrade Essentials” steps at the top of this page. No major breaking changes between v4 and v5.

Upgrading from v3 to v4

Breaking Changes

  • Laravel 5.8 support dropped - Requires Laravel 6.0+
  • PHP 7.2.5+ required (was 7.1)
  • Unique constraints now enforced at database level
  • Changed PermissionRegistrar::initializeCache() from private to public
  • Collections changed from Support\Collection to Eloquent\Collection

Database Changes

Unique constraints are now enforced at the database level. Create a migration to add these constraints:
Schema::table('permissions', function (Blueprint $table) {
    $table->unique(['name', 'guard_name']);
});

Schema::table('roles', function (Blueprint $table) {
    $table->unique(['name', 'guard_name']);
});

Upgrading from v2 to v3

  • PHP 7.2+ required
  • Laravel 5.8+ required
  • No other breaking changes

Upgrading from v1 to v2

Upgrading from v1 to v2 requires significant database and code changes. There is no automatic migration.
V2 introduced a complete restructure of the database schema and code architecture.

Manual Migration Required

You’ll need to:
  1. Manually migrate your data to the new structure
  2. Update all code to use new methods
  3. Remove old laravel-permission.php config
  4. Publish and configure new permission.php config
Migration Helper: @fabricecw’s migration gist may help with data migration.

Getting Help

If you encounter issues during upgrade:
  1. Review the complete Changelog
  2. Check GitHub Issues
  3. Consult the Release Notes
  4. See the Troubleshooting guide
Always test upgrades in a development environment before deploying to production.

Build docs developers (and LLMs) love