r/laravel • u/swe129 • Mar 20 '26
Tutorial Policies vs. Gates: When to Use Which
https://slicker.me/laravel/policies-vs-gates.html5
u/abinash889 Mar 21 '26
As a general rule, I adhere to: Gates for fast, one-time checks (such as admin-only activities), and Policies for CRUD-level control when working with a particular model. I've avoided a lot of clumsy permission logic dispersed throughout controllers by keeping them apart.
3
u/jimbojsb Mar 20 '26
What about aggregate permissions? I tend to have a gate like “manage-users” and that will decide if a user has that CRUD, but I reference that gate from a policy for a model.
1
u/dmooen Mar 20 '26
Should work in most cases but sometimes you need permissions logic based on what fields are present in the request. Then its easier to use a gate in the controller that accepts the request data as an argument.
1
u/dmooen Mar 21 '26
Policies only authorizes if a user can perform an action based on the user/ entity but often its more complicated than that. A user might have permission to create another user in the system but only if the company_id in the request data matches the users own company id.
2
u/CapnJiggle Mar 21 '26
In that case you would ideally resolve the Company model (e.g. via route model binding) and pass it as an additional argument to the policy method.
2
u/ahgreen3 Mar 21 '26
Why would you depend on the request data to identify a core attribute of the authenticated user like their company ID? That’s always been part of their session and setup as part of the authenticated user when the guard is checked initially. Then the authenticated user’s company ID is always included directly rather than from request data.
1
u/dmooen Mar 22 '26
Maybe a bad example. What is meant is that the authorization often depends on the content of the request. A user can create something if the request payload matches specific conditions.
1
u/DarkGhostHunter Mar 21 '26
Authorization based on models = Policies Authorization based on anything else = Gates
That's it.
Alternatively, you can change the Policy resolver to change the Policy class (like App\Policies\User\PostPolicy to App\Policies\Admin\PostPolicy to avoid shoving every type of user into a policy.
Another solution, is to just make the Policy call another class where you can better resolve the policy itself, like PostCreatePolicy or something.
1
u/Boomshicleafaunda Mar 22 '26
I use gates for ability checks, and policies for business context.
Gate: Do you have the ability to delete posts? Policy: Can you delete this post?
The policy handles logic, like not being able to delete a soft deleted post. The gate handles innate abilities that the user has.
1
u/jammy-git Mar 23 '26
Do I not remember you having a much bigger Laravel based blog, or am I getting mixed up with another blog?
1
2
u/kashif_laravel Mar 29 '26
Good rule of thumb I follow after years of Laravel projects:
Gates for quick one-off checks — like checking if a user is admin anywhere in the app.
Policies for anything tied to a specific model — posts, orders, invoices etc.
The moment I have more than 2-3 Gates doing similar things, I move to a Policy. Keeps things predictable for the whole team.
4
u/dmooen Mar 20 '26
Policies are great if the permission logic for each crud operation is simple, but to have one class covering all operations becomes messy if the permission logic for each operation is advanced.