Gates vs Policies in Laravel: What’s the Difference and When Should You Use Each?

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.

Leave a Reply

Your email address will not be published. Required fields are marked *