Migrating from Other Packages
Warden provides migrators to help you transition from other popular Laravel permission packages. These migrators preserve all your existing roles, abilities, permissions, and assignments while converting them to Warden’s schema.
Supported Packages
Section titled “Supported Packages”Migrating from Spatie Laravel Permission
Section titled “Migrating from Spatie Laravel Permission”Prerequisites
Section titled “Prerequisites”Before migrating, ensure you have:
- Installed Warden alongside Spatie Laravel Permission
- Published and run Warden’s migrations
- Added the
HasRolesAndAbilitiestrait to your User model
Configuration
Section titled “Configuration”Configure the Spatie table names in config/warden.php:
'migrators' => [ 'spatie' => [ 'tables' => [ 'permissions' => env('WARDEN_SPATIE_PERMISSIONS_TABLE', 'permissions'), 'roles' => env('WARDEN_SPATIE_ROLES_TABLE', 'roles'), 'model_has_permissions' => env('WARDEN_SPATIE_MODEL_HAS_PERMISSIONS_TABLE', 'model_has_permissions'), 'model_has_roles' => env('WARDEN_SPATIE_MODEL_HAS_ROLES_TABLE', 'model_has_roles'), 'role_has_permissions' => env('WARDEN_SPATIE_ROLE_HAS_PERMISSIONS_TABLE', 'role_has_permissions'), ], 'model_type' => env('WARDEN_SPATIE_MODEL_TYPE', 'user'), ],],Running the Migration
Section titled “Running the Migration”use Cline\Warden\Migrators\SpatieMigrator;use App\Models\User;
$migrator = new SpatieMigrator(User::class);$migrator->migrate();What Gets Migrated
Section titled “What Gets Migrated”The Spatie migrator transfers:
- Roles: All roles with their names and guard names
- Permissions: All permissions converted to Warden abilities (preserving guard_name)
- Model Role Assignments: User-to-role associations
- Model Permissions: Direct user permissions
- Role Permissions: Permissions assigned to roles
Important: The Spatie migrator preserves the guard_name from your existing Spatie roles and permissions. This ensures guard isolation is maintained during migration. See Multi-Guard Support for details.
Migration Scenarios Covered
Section titled “Migration Scenarios Covered”- ✅ Users with only roles
- ✅ Users with only direct permissions
- ✅ Users with both roles AND direct permissions
- ✅ Roles with permissions but no users assigned
- ✅ Multiple users sharing the same role
- ✅ Users with multiple roles
Example
Section titled “Example”If you have this Spatie setup:
// Spatie$user->assignRole('admin');$user->givePermissionTo('edit-articles');$admin = Role::findByName('admin');$admin->givePermissionTo('manage-users');After migration, you’ll have:
// Warden equivalent (already migrated, no need to run this)$user->hasRole('admin'); // true$user->can('edit-articles'); // true (direct permission)$user->can('manage-users'); // true (via admin role)Migrating from Silber Bouncer
Section titled “Migrating from Silber Bouncer”Prerequisites
Section titled “Prerequisites”Before migrating, ensure you have:
- Installed Warden alongside Silber Bouncer
- Published and run Warden’s migrations
- Added the
HasRolesAndAbilitiestrait to your User model
Configuration
Section titled “Configuration”Configure the Bouncer table names in config/warden.php:
'migrators' => [ 'bouncer' => [ 'tables' => [ 'abilities' => env('WARDEN_BOUNCER_ABILITIES_TABLE', 'abilities'), 'roles' => env('WARDEN_BOUNCER_ROLES_TABLE', 'roles'), 'assigned_roles' => env('WARDEN_BOUNCER_ASSIGNED_ROLES_TABLE', 'assigned_roles'), 'permissions' => env('WARDEN_BOUNCER_PERMISSIONS_TABLE', 'permissions'), ], 'entity_type' => env('WARDEN_BOUNCER_ENTITY_TYPE'), ],],Running the Migration
Section titled “Running the Migration”use Cline\Warden\Migrators\BouncerMigrator;use App\Models\User;
// Default guard (uses 'guard' config value)$migrator = new BouncerMigrator(User::class);$migrator->migrate();
// Specify a custom guard$apiMigrator = new BouncerMigrator(User::class, 'migration', 'api');$apiMigrator->migrate();Note: Since Bouncer doesn’t have built-in guard support, you can specify which guard the migrated roles and abilities should use. See Multi-Guard Support for more information.
What Gets Migrated
Section titled “What Gets Migrated”The Bouncer migrator transfers:
- Roles: All roles with their names and titles
- Abilities: All abilities with complete metadata (title, only_owned, options, entity scoping)
- User Role Assignments: User-to-role associations
- User Permissions: Direct user permissions (both allowed and forbidden)
- Role Permissions: Permissions assigned to roles (both allowed and forbidden)
Ability Metadata Preserved
Section titled “Ability Metadata Preserved”Bouncer abilities have rich metadata that Warden preserves:
title: Human-readable ability titleonly_owned: Whether the ability only applies to owned resourcesoptions: JSON options for fine-grained controlentity_id/entity_type: Entity scoping (migrated tosubject_id/subject_type)
Migration Scenarios Covered
Section titled “Migration Scenarios Covered”- ✅ Users with only roles
- ✅ Users with only direct permissions
- ✅ Users with both roles AND direct permissions
- ✅ Forbidden permissions (on both users and roles)
- ✅ Roles with permissions but no users assigned
- ✅ Multiple users sharing the same role
- ✅ Users with multiple roles
- ✅ Roles without titles (title defaults to role name)
Example
Section titled “Example”If you have this Bouncer setup:
// BouncerBouncer::assign('admin')->to($user);Bouncer::allow($user)->to('edit-articles');Bouncer::allow('admin')->to('manage-users');Bouncer::forbid($user)->to('delete-posts');After migration, you’ll have:
// Warden equivalent (already migrated, no need to run this)$user->hasRole('admin'); // true$user->can('edit-articles'); // true (direct permission)$user->can('manage-users'); // true (via admin role)$user->cannot('delete-posts'); // true (forbidden)Post-Migration Steps
Section titled “Post-Migration Steps”After successfully migrating:
- Test thoroughly: Verify all permissions work as expected
- Update code: Replace old package facades/helpers with Warden equivalents
- Remove old package: Once confident, uninstall the previous package
- Clean up: Drop the old package’s tables if no longer needed
Migration in Production
Section titled “Migration in Production”For production environments:
- Backup your database before migrating
- Test migration in staging first
- Plan for downtime or use a maintenance window
- Monitor logs during and after migration
- Have a rollback plan ready
Troubleshooting
Section titled “Troubleshooting”Missing Users
Section titled “Missing Users”The migrator skips assignments for non-existent users. Check logs for:
User not found: 12345Missing Roles/Abilities
Section titled “Missing Roles/Abilities”The migrator skips assignments referencing non-existent roles or abilities. Check logs for:
Role not found: 98765Ability not found: 45678Guard Name Issues
Section titled “Guard Name Issues”For Spatie migrations: Guard names are preserved automatically from your Spatie tables.
For Bouncer migrations: Bouncer doesn’t have guard support, so specify the target guard when creating the migrator:
// Migrate to 'api' guard instead of default 'web'$migrator = new BouncerMigrator(User::class, 'migration', 'api');See Multi-Guard Support for more information on working with multiple guards.
Custom Migrators
Section titled “Custom Migrators”If you’re migrating from a different package or have custom requirements, you can create your own migrator by implementing the MigratorInterface:
namespace App\Migrators;
use Cline\Warden\Contracts\MigratorInterface;
class CustomMigrator implements MigratorInterface{ public function migrate(): void { // Your migration logic here }}The interface is intentionally simple with a single migrate() method, giving you full control over the migration process.