Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon Can I use a team as the default scope for feature checks in Laravel Pennant


Can I use a team as the default scope for feature checks in Laravel Pennant


Yes, you can use a team as the default scope for feature checks in Laravel Pennant. By default, Laravel Pennant checks feature flags against the currently authenticated user, but it allows customization of the default scope to suit your application's needs.

How to Use a Team as the Default Scope

Instead of checking features against the user every time via `Feature::for($user->team)`, you can configure Pennant to automatically use the authenticated user's team as the default scope. This is done by defining a scope resolver in one of your application's service providers, typically the `AppServiceProvider`. For example:

php
namespace App\Providers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
use Laravel\Pennant\Feature;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Feature::resolveScopeUsing(fn ($driver) => Auth::user()?->team);
    }
}

With this setup, calling `Feature::active('billing-v2')` will implicitly check the feature against the authenticated user's team, equivalent to `Feature::for($user->team)->active('billing-v2')`[1].

Defining Features for a Team Scope

When defining features that use a team as the scope, your feature definition closure should expect a `Team` model instead of a `User`. For example:

php
use App\Models\Team;
use Carbon\Carbon;
use Illuminate\Support\Lottery;
use Laravel\Pennant\Feature;

Feature::define('billing-v2', function (Team $team) {
    if ($team->created_at->isAfter(new Carbon('1st Jan, 2023'))) {
        return true;
    }

    if ($team->created_at->isAfter(new Carbon('1st Jan, 2019'))) {
        return Lottery::odds(1 / 100);
    }

    return Lottery::odds(1 / 1000);
});

This closure uses the `Team` instance to determine if the feature is active based on the team's creation date and some probabilistic rollout[1].

Handling Nullable Scopes

If there is a chance that the scope could be `null` (for example, in unauthenticated routes, Artisan commands, or queued jobs), you should make your feature definitions accept nullable scopes and handle the `null` case accordingly. Pennant will return `false` automatically if the scope is `null` and the feature does not support it, but you can customize this behavior:

php
Feature::define('new-api', fn (Team|null $team) => $team === null ? false : /* your logic here */);

This ensures your feature checks do not break in contexts where there is no authenticated user or team[1].

Summary

- You can use a team as the default scope in Laravel Pennant by configuring the default scope resolver to return the authenticated user's team.
- This avoids having to explicitly call `Feature::for($user->team)` every time you check a feature.
- Feature definitions should expect the `Team` model as the scope parameter.
- Handle nullable scopes to avoid issues in unauthenticated or background contexts.
- This approach is recommended to centralize feature flag scoping logic and keep your code cleaner[1][2].

This flexibility makes Laravel Pennant suitable for feature flagging not just at the user level but also at broader scopes like teams or other models.

Citations:
[1] https://laravel.com/docs/12.x/pennant
[2] https://elliotderhay.com/blog/how-to-make-laravel-pennant-features-that-apply-globally
[3] https://www.honeybadger.io/blog/a-guide-to-feature-flags-in-laravel/
[4] https://laracasts.com/discuss/channels/laravel/laravel-pennant-how-to-control-a-feature-for-all-users
[5] https://dev.to/saurabh-dhariwal/how-to-manage-feature-flags-with-laravel-pennant-in-2024-1phb
[6] https://laracasts.com/comments/26789
[7] https://www.reddit.com/r/PHPhelp/comments/199o0h2/im_working_with_laravel_pennant_and_i_want_to/
[8] https://redberry.international/laravel-pennant-feature-flagging-made-easy/