Database schema & key types
Five tables back the package. Table names come from table_names; column names are fixed:
| Table | Columns | Keys |
|---|---|---|
permissions | id, name (unique), description (jsonb, nullable), timestamps | Auto-incrementing id. |
roles | id, name (unique), description (jsonb, nullable), timestamps | Auto-incrementing id. |
permission_role | permission_id, role_id | Both foreign keys cascade on delete; primary key (permission_id, role_id). |
model_roles | role_id, model_type, model_id | role_id cascades on delete; index (model_id, model_type); primary key (role_id, model_id, model_type). |
model_permissions | permission_id, model_type, model_id | permission_id cascades on delete; index (model_id, model_type); primary key (permission_id, model_id, model_type). |
Holder links are polymorphic (model_type + model_id), so any Eloquent model can hold roles and permissions — not just users. Custom morph-map aliases are stored in the pivots as they are everywhere else in Laravel.
Holder key type
key_type describes the models that hold roles and permissions — never this package’s own tables, which always keep an auto-incrementing key. It types the model_id column on the two polymorphic pivots:
| key_type | model_id column | Use when your holders… |
|---|---|---|
bigint | unsignedBigInteger | use Laravel’s default auto-incrementing keys (the default) |
uuid | uuid | use HasUuids |
ulid | ulid | use HasUlids |
Set it before you publish and run the migrations — the schema freezes at release:
PERMISSIONS_KEY_TYPE=uuiduse Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Foundation\Auth\User as Authenticatable;
use RoundlyConsulting\Permissions\Concerns\HasRoles;
class User extends Authenticatable
{
use HasRoles;
use HasUuids; // pairs with PERMISSIONS_KEY_TYPE=uuid
}Unset or blank reads as bigint; an unrecognized value throws the toolkit’s InvalidConfigurationException rather than silently building bigint keys.
Hard deletes by design
Roles and permissions do not use soft deletes: the unique name index would clash with soft-deleted rows, and every pivot cascades on delete — removing a role or permission removes its grants with it.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.