cartalyst/permissions
Cartalyst Permissions is a PHP package for role-based access control, letting you define roles and permissions and check user access in Laravel applications. It provides a simple API for assigning, inheriting, and validating permissions.
Choosing an authorization model before choosing a library. This package is a compact, readable reference implementation of the classic RBAC graph — named permissions, roles as permission containers, assignment resolved through a storage-agnostic container. It gives product and engineering a shared vocabulary (roles vs. permissions vs. entitlements vs. plan features) and a concrete artifact to argue against before anyone commits a schema. That alignment work is valuable even if the code is never installed.
Drawing the storage/enforcement line deliberately. The package stores and resolves permission strings; it does not enforce. That split is a product decision: policy data belongs in your database, policy evaluation belongs in gates, policies, or middleware. Framing it this way early prevents permission checks from scattering across controllers and templates, and keeps a future repackaging effort a migration + seeder rather than a multi-sprint refactor.
Build vs. buy vs. borrow for authorization. It sits at the "vendor a tiny readable component" end of the spectrum, alongside Laravel's native Gate/Policy, spatie/laravel-permission, and externalized engines (OpenFGA, Ory Keto, OPA). Placing your product on that spectrum forces the only question that matters: how much authorization complexity is genuinely core to the product, and how much is commodity plumbing?
Feature gating and packaging. Once permissions are first-class named records, plan-tier gating ("Pro includes export.reports"), seat limits, and admin-delegated access become configuration edits rather than conditionals. That directly feeds pricing, packaging, and add-on entitlement work — but only if permissions are modeled as data, which is exactly the pattern this package demonstrates.
Multi-tenancy scope, decided early. Because the container is storage-agnostic, it surfaces the question of whether roles are global or tenant-scoped. Cheap to decide at schema-design time, expensive to retrofit into a live permission graph.
Enterprise-sales and compliance readiness. SOC 2 and security questionnaires ask "who can access what, and who changed it?" A normalized role/permission store with an audit trail on changes is the substrate for answering that. This package contributes the resolution semantics; you still own the store and the audit log.
Roadmap signal — not a roadmap item. The package is a reference and a semantics donor, not a strategic dependency. Nothing in a product roadmap should hinge on its release cadence.
Consider it when:
users.create vs. users.* vs. *) before committing to a data model.Gate::before bridge, and an explain tooling command. There is no service provider, facade, config, or migration in the box.NOASSERTION; Cartalyst's historical model has been commercial/proprietary). This is a gate, not a formality.Look elsewhere when:
spatie/laravel-permission ships migrations, a service provider, middleware, Blade directives, and an active maintenance surface.Gate::before super-admin shortcut are lighter and have no dependency risk.To executives: This is not a "buy the vendor's product" decision — it is a scoping decision about how much proprietary authorization logic we want to own. Authorization is commodity infrastructure; the value is in the product rules (which plan gets which capability, which admin can delegate what), not in the evaluator. This package is a small, readable reference for the RBAC model we'd adopt anyway. Treat it as a design input during the spike, and expect the production implementation to be either our own thin layer or a maintained community package — not this dependency at runtime.
To engineering: The package is a permission-string resolver with no Laravel integration, no persistence, and no enforcement — no service provider, facade, config, migrations, or middleware. What it contributes is wildcard and inheritance semantics, which is the genuinely fiddly part worth borrowing. Everything else — schema, repository, cache strategy, Gate::before bridge, ability registry, and an permissions:explain artisan command — is ours to build and own. The discipline that matters: every call site goes through Gate, @can, or a single injected gateway, never a direct container call. That keeps a swap to spatie/laravel-permission or native policies a one-class change.
Risks to state plainly: one star, zero dependents, last release December 2020, license reported as NOASSERTION, and no upstream maintenance signal. Adoption means fork-and-own inside the monorepo with a named maintainer and a documented exit path. Recommendation: use it as a semantics reference in the spike, ship with a native Gate/Policy implementation or a maintained package, and revisit a fork only if the wildcard-resolution logic proves to be a meaningful ongoing cost.
How can I help you explore Laravel packages today?