Laravel Pennant Package – Feature Flag Tutorial

Last updated on April 15, 2023

Laravel 10 introduced a new package Pennant that manages your Laravel application’s features flags. It has the ability to hide and show the application’s features based on cases. It is created by the Laravel team.

But when to use Laravel Pennant? Let’s understand it by an example.

Assume, you’re releasing a new feature that should be accessible only to premium users. To do that you need an if-statement somewhere in your application that should hide new features from freemium users, right? The Laravel Pennant package provides a more advanced and easier way to do that.

How to use the Laravel Pennant?

In this article, we will be learning to use the Pennant package in the Laravel application by implementing a real example in which we will be allowing premium users to access the feature.

So, we have a Laravel 10 application that is installed with the Breeze package. Additionally, in this application, we have a Courses feature that has to be accessible only to premium users. Also, an additional column is_subscriber in the users table that differentiates the premium and freemium users.

Install Laravel Pennant Package

To install Pennant into your application, run below composer command.

composer require laravel/pennant

Once it is installed, you need to run publish the Pennant’s configuration and migration files through vendor:publish artisan command.

php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider"

After, publishing the configurations, you need to run one more command to create a features table in the database. Run below artisan command,

php artisan migrate

The features table contains 5 columns id, name, scope, and value. Let’s understand each column’s function.

  • name: it stores the feature’s name
  • scope: it stores the namespace of the feature’s class that has to manage.
  • value: it stores bool values. Pennant acts on the feature based on this value.

Defining Feature:

The Pennant package provides a define() method that defines the feature. To define a feature in your application, You need to use the define() method from the Feature facade.

Go to app/Providers directory and open the AppServiceProvider.php. Add the below script in the boot() method of AppServiceProvider class that defines the feature for course management.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Pennant\Feature;
use App\Models\User;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Feature::define('course-management', function(User $user){
            return (bool)$user->is_subscriber;
        });
    }
}

In the above script, we defined a feature for course management through the define() method. The define() method takes two parameters,

  • First Parameter: Feature name.
  • Second Parameter: A callback function.

In the callback function, we passed the User $user parameter that returns the current logged-in user. It returns a bool value based on the is_subscriber column from users table.

Apply Feature on Course Management Through Directive in Blade:

Pennant also provides a directive that checks if the user is authorized for the feature. Let’s use a feature directive to hide Courses for the freemium user.

Go to resources/views/layouts directory and open the navigation.blade.php. Add below HTML code with the feature directive.

@feature('course-management')
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
    <x-nav-link :href="route('courses')" :active="request()->routeIs('courses')">
        {{ __('Courses') }}
    </x-nav-link>
</div>
@endfeature

This feature directive checks if the user is premium and shows the Courses link in the menu in the dashboard.

But what about if a user directly accesses through the URL?

http://127.0.0.1:8000/courses

It will be accessible which is because it is hidden in the menu only. To remove the access from the freemium user we need middleware to protect the course management route.

Protect Feature Through Middleware:

To protect the Pennant feature, you need to register the middleware in the $middlewareAliases array. Open the kernel.php from app/Http directory and register features middleware by adding the below script into the $middlewareAliases array.

'features' => EnsureFeaturesAreActive::class,

Also, add the following namespace at the top of the kernel.php file.

use Laravel\Pennant\Middleware\EnsureFeaturesAreActive;

Next, apply middleware on the course route. To apply to add the Pennant features middleware on the route, you need to use the middleware() method with argument.

Route::middleware('auth')->group(function () {
    Route::get('/courses', [CourseController::class, 'index'])->name('courses')->middleware('features:course-management');
});

Now, courses route is protected and accessible only to premium users.

Test Pennant Feature with Premium and Freemium User:

Let’s test the course management feature with premium and freemium user. I registered two users,

  • John Smith: Freemium user
  • Ronald: Premium user

For the freemium user, the is_subscriber column value is 0 while for premium it is 1. Look at the below screenshot of users table.

Pennant package inserts data for each user for the feature that needs to be managed. Look at the below screenshot of the features table.

In the features table, the value is false for the freemium user whose id is 1 which means course management won’t be accessible. While course management will be accessible for the user that value is true.

Below is the screenshot of freemium user John smith’s dashboard

Let’s access courses through the URL and check if it is accessible.

Now, let’s check the dashboard of Premium user Ronald


Written by
I am a skilled full-stack developer with extensive experience in creating and deploying large and small-scale applications. My expertise spans front-end and back-end technologies, along with database management and server-side programming.

Share on:

Related Posts

Tags: Laravel,