Laravel provides two main mechanisms for handling authorization: Gates and Policies. Both determine whether a user is allowed to perform a specific action — but they serve different purposes, scale differently, and fit different architectural needs.
In this post, we’ll break down the differences, show real PHP examples, and give practical guidance on when to use each tool.
What Is a Gate?
A Gate is essentially a simple closure‑based authorization check.
It returns
true
or
false
and is not tied to any specific model.
Gates are perfect for global permissions or one‑off checks.
Example: Allow only admins to access the admin panel
app/Providers/AuthServiceProvider.php
use Illuminate\Support\Facades\Gate;
public function boot()
{
Gate::define('view-admin-panel', function ($user) {
return $user->role === 'admin';
});
}
Using a Gate in a controller
public function index()
{
Gate::authorize('view-admin-panel');
return view('admin.dashboard');
}
Using a Gate in Blade
@can('view-admin-panel')
<a href="/admin">Admin Panel</a>
@endcan
When Gates make sense
- The permission is not tied to a model
- The logic is simple
- You need one or two checks, not a whole system
What Is a Policy?
A Policy is a dedicated class that contains authorization logic for a specific model.
It’s structured, scalable, and ideal for CRUD‑style permissions.
Creating a Policy
php artisan make:policy PostPolicy --model=Post
Example
PostPolicy
class PostPolicy
{
public function view(User $user, Post $post)
{
return true; // anyone can view
}
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
Registering the Policy (if Laravel doesn’t auto‑discover it)
protected $policies = [
Post::class => PostPolicy::class,
];
Using a Policy in a controller
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$post->update($request->all());
}
Using a Policy in Blade
@can('update', $post)
<button>Edit</button>
@endcan
When Policies make sense
- The permission is tied to a specific model
- You have multiple actions (view, create, update, delete)
- The project is large and needs structure
Gates vs Policies: Side‑by‑Side Comparison
| Feature | Gates | Policies |
|---|---|---|
| Model‑specific | ❌ No | ✅ Yes |
| Scalability | Low | High |
| Structure | Single functions | Organized class |
| Best for | Global checks | CRUD permissions |
| Typical use case | Admin panel access | Managing posts, orders, invoices |
When Gates Are a Bad Fit
Avoid Gates when:
- You have many checks for the same model
- Authorization logic is growing
- You start duplicating conditions across controllers
At that point, a Policy is the right tool.
When Policies Are Overkill
Avoid Policies when:
- You only need one simple check
- The permission is not related to a model
- You don’t need a whole class for a single rule
In those cases, a Gate is perfect.
Real‑World Example: Using Both Together
Imagine a blog system:
- Gate: access to the admin dashboard (
view-admin-panel
)
- Policy: permissions for managing posts (
PostPolicy
)
This is the recommended pattern:
- Global actions → Gates
- Model actions → Policies
Conclusion
Laravel gives you two powerful authorization tools — and each has a clear purpose.
- Gates are simple, global, and great for quick checks.
- Policies are structured, scalable, and ideal for model‑based permissions.
If your project grows, Policies will keep your authorization logic clean and maintainable.
If you just need a quick global rule, a Gate is the fastest solution.








