Build With Abdallah logo Build With Abdallah Software · AI · Automation
Tutorial 3 min read Jun 05, 2026

Mastering Feature Flags in Laravel 10 with Laravel Pennant

A
Abdallah Mohamed
Senior Full-Stack Engineer
Mastering Feature Flags in Laravel 10 with Laravel Pennant

Mastering Feature Flags in Laravel 10 with Laravel Pennant

Feature flags are a powerful technique for managing the release of new features in software development. They allow developers to enable or disable features in an application without deploying new code. This is crucial for gradual rollouts, A/B testing, and quick rollbacks if something goes wrong. Laravel Pennant is a package that simplifies the implementation of feature flags in Laravel applications, making it easier to manage features dynamically.

In this tutorial, we will explore how to use Laravel Pennant to implement feature flags in a Laravel 10 application. By the end, you will be able to control feature access dynamically and improve your deployment process.

Prerequisites

Before we start, ensure you have the following installed on your machine:

  • PHP 8.1 or higher
  • Composer
  • Laravel 10
  • Node.js & npm (for frontend assets)

You can install Laravel 10 via Composer with the following command:

composer create-project laravel/laravel feature-flags-example

Navigate into the project directory:

cd feature-flags-example

Install Laravel Pennant using Composer:

composer require laravel/pennant

Project Structure

Once you have installed Laravel and Laravel Pennant, your project structure should look like this:

feature-flags-example/
├── app/
├── bootstrap/
├── config/
│   ├── pennant.php
├── database/
├── public/
├── resources/
├── routes/
│   ├── web.php
├── storage/
├── tests/
├── vendor/
├── .env
└── composer.json

Step 1: Setting Up Laravel Pennant

First, we need to publish the configuration file for Laravel Pennant. This will allow us to customize its behavior as needed.

Run the following command to publish the configuration file:

php artisan vendor:publish --tag=pennant-config

This will create a pennant.php file in the config directory. Open this file to review the default settings. It contains options for storage and drivers that control how feature flags are managed.

Step 2: Defining Feature Flags

Let's define a feature flag in our application. We'll create a simple feature flag to control access to a new dashboard.

Open the routes/web.php file and add the following code:

use Illuminate\Support\Facades\Route;
use Laravel\Pennant\Feature;

Route::get('/dashboard', function () {
    if (Feature::active('new-dashboard')) {
        return view('new-dashboard');
    }

    return view('old-dashboard');
});

In this code, we use the Feature::active() method to check if the new-dashboard feature is enabled. If it is, we display the new-dashboard view; otherwise, we show the old-dashboard view.

Step 3: Managing Feature Flags

Now, let's see how we can enable or disable the new-dashboard feature flag. We can do this from the command line using Artisan commands.

To enable the new-dashboard feature, run:

php artisan pennant:enable new-dashboard

To disable the new-dashboard feature, use:

php artisan pennant:disable new-dashboard

These commands modify the current state of the feature flag, allowing you to control feature access without changing any code.

To verify the status of your feature flags, you can use:

php artisan pennant:status

This command will list all defined feature flags and their current states.

In this step, we have successfully managed our feature flags using Artisan commands, providing a flexible way to control feature availability in a Laravel application.


```markdown
## Step 4: Creating a Custom Feature Driver

Laravel Pennant allows you to define custom feature drivers if you need more control over how feature flags are stored or evaluated. Let's create a custom feature driver that stores feature flags in a JSON file.

First, create a new directory for our custom driver:

```bash
mkdir app/FeatureDrivers

Create a new PHP file for the driver:

touch app/FeatureDrivers/JsonFeatureDriver.php

Open JsonFeatureDriver.php and add the following code:

<?php

namespace App\FeatureDrivers;

use Laravel\Pennant\Contracts\Driver;

class JsonFeatureDriver implements Driver
{
    protected $path;

    public function __construct()
    {
        $this->path = storage_path('app/features.json');
    }

    public function get($feature, $scope)
    {
        $features = $this->loadFeatures();
        return $features[$feature] ?? false;
    }

    public function set($feature, $scope, $value)
    {
        $features = $this->loadFeatures();
        $features[$feature] = $value;
        $this->saveFeatures($features);
    }

    protected function loadFeatures()
    {
        if (!file_exists($this->path)) {
            return [];
        }

        return json_decode(file_get_contents($this->path), true) ?? [];
    }

    protected function saveFeatures(array $features)
    {
        file_put_contents($this->path, json_encode($features));
    }
}

Next, register this driver in config/pennant.php:

'driver' => env('PENNANT_DRIVER', 'json'),

'drivers' => [
    'json' => [
        'driver' => App\FeatureDrivers\JsonFeatureDriver::class,
    ],
],

This configuration tells Laravel Pennant to use the JsonFeatureDriver for managing feature flags.

Step 5: Testing Feature Flags

To ensure our feature flags work as expected, let's write a simple test. Open the tests/Feature/ExampleTest.php file and add the following test:

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Laravel\Pennant\Feature;

class FeatureFlagTest extends TestCase
{
    public function test_new_dashboard_feature_flag()
    {
        Feature::set('new-dashboard', true);

        $response = $this->get('/dashboard');

        $response->assertViewIs('new-dashboard');

        Feature::set('new-dashboard', false);

        $response = $this->get('/dashboard');

        $response->assertViewIs('old-dashboard');
    }
}

Run the test using PHPUnit:

php artisan test

This test verifies that the correct view is returned based on the state of the new-dashboard feature flag.

Complete Working Example

Here is a summary of the key files and their contents:

routes/web.php

use Illuminate\Support\Facades\Route;
use Laravel\Pennant\Feature;

Route::get('/dashboard', function () {
    if (Feature::active('new-dashboard')) {
        return view('new-dashboard');
    }

    return view('old-dashboard');
});

app/FeatureDrivers/JsonFeatureDriver.php

<?php

namespace App\FeatureDrivers;

use Laravel\Pennant\Contracts\Driver;

class JsonFeatureDriver implements Driver
{
    protected $path;

    public function __construct()
    {
        $this->path = storage_path('app/features.json');
    }

    public function get($feature, $scope)
    {
        $features = $this->loadFeatures();
        return $features[$feature] ?? false;
    }

    public function set($feature, $scope, $value)
    {
        $features = $this->loadFeatures();
        $features[$feature] = $value;
        $this->saveFeatures($features);
    }

    protected function loadFeatures()
    {
        if (!file_exists($this->path)) {
            return [];
        }

        return json_decode(file_get_contents($this->path), true) ?? [];
    }

    protected function saveFeatures(array $features)
    {
        file_put_contents($this->path, json_encode($features));
    }
}

config/pennant.php

'driver' => env('PENNANT_DRIVER', 'json'),

'drivers' => [
    'json' => [
        'driver' => App\FeatureDrivers\JsonFeatureDriver::class,
    ],
],

Common Errors and Fixes

  1. Error: "Class 'App\FeatureDrivers\JsonFeatureDriver' not found"

    • Fix: Ensure the namespace and class name in JsonFeatureDriver.php match the reference in config/pennant.php.
  2. Error: "Call to undefined method Laravel\Pennant\Feature::set()"

    • Fix: Check that you are using the correct namespace and that Laravel Pennant is properly installed.
  3. Error: "File not found" for features.json

    • Fix: Ensure the storage/app directory is writable, or create the features.json file manually.

Conclusion

In this tutorial, we explored how to implement feature flags in a Laravel 10 application using Laravel Pennant. We covered setting up the package, defining feature flags, managing them via Artisan commands, creating a custom driver, and testing the implementation. Feature flags are a valuable tool for managing feature rollouts and improving deployment strategies.

Sources