What is Laravel Pennant?
Laravel Pennant is a simple, lightweight feature flag package. Feature flags let you incrementally roll out new application features with confidence, run A/B tests on new interface designs, complement trunk-based development strategies, and more.Feature Flag Flow
Feature flags decouple deployment from release — deploy code to production without exposing it to users until you’re ready.Installation
1
Install the package
Install Pennant via Composer:
2
Publish configuration and migrations
Publish Pennant’s config file and database migrations:
3
Run migrations
Create the
features table used by the database driver:Configuration
After publishing, the config file is located atconfig/pennant.php. You can set the default storage driver here.
Defining Features
Closure-based Features
Define features using theFeature facade’s define method, typically in a service provider’s boot method. The closure receives the feature’s “scope” — usually the authenticated user.
- Always ON for internal team members
- Always OFF for high-traffic customers
- Randomly enabled for 1% of everyone else
If a feature definition only returns a Lottery, you can omit the closure entirely:
Class-based Features
Class-based features do not need to be registered in a service provider. Generate one with the Artisan command:app/Features. Implement the resolve method:
Customizing the Stored Feature Name
By default, Pennant stores the fully qualified class name. Use theName attribute to decouple the stored name from the class name:
Intercepting Feature Checks (before method)
Class-based features may define a before method that runs in-memory before the stored value is retrieved. If a non-null value is returned, it overrides the stored value for the duration of the request.
Checking Features
Feature::active() / Feature::inactive()
Use the active method to check whether a feature is active. By default, the currently authenticated user is used as the scope.
Conditional Execution (when / unless)
Use when to fluently execute a closure when a feature is active:
unless is the inverse — the first closure runs when the feature is inactive:
The HasFeatures Trait
Add HasFeatures to your User model to check features directly from the model:
Blade Directive
Pennant provides@feature and @featureany Blade directives:
Middleware
UseEnsureFeaturesAreActive to require features to be active before a route can be accessed. If any listed feature is inactive, a 400 Bad Request response is returned.
whenInactive:
In-Memory Cache
Pennant caches resolved feature values in memory for the duration of a request. The same feature will not trigger additional database queries when checked multiple times. Manually flush the cache with:Scope
Specifying the Scope
Use thefor method to check a feature against a specific scope:
Default Scope
Customize the default scope usingFeature::resolveScopeUsing:
Feature::active('billing-v2') automatically uses the team scope.
Nullable Scope
If the scope isnull (unauthenticated routes, Artisan commands, queued jobs) and the feature definition does not handle null, Pennant returns false. Use nullable types to handle this:
Rich Feature Values
Features can return values other than booleans. This is useful for A/B testing:value method:
When using rich values, a feature is considered “active” when it has any value other than
false.when:
Retrieving Multiple Features
Usevalues to retrieve multiple features at once:
all to retrieve all defined features:
all results, call discover in a service provider:
app/Features.
Eager Loading
Avoid N+1 queries when checking features in a loop by usingload:
Updating Values
Manual Updates
Toggle a feature on or off usingactivate and deactivate:
Bulk Updates
Apply a value to all scopes at once:Purging Features
Remove all stored values for a feature usingpurge:
Testing
Re-defining Features
The easiest way to control feature values in tests is to re-define the feature:tab=Pest
tab=PHPUnit
tab=Pest
tab=PHPUnit
Test Store Configuration
Configure the Pennant store for testing inphpunit.xml:
Custom Drivers
If the built-in drivers don’t meet your needs, implement theLaravel\Pennant\Contracts\Driver interface:
Feature::extend in a service provider:
config/pennant.php:
Summary
Next Steps
Error Handling
Learn how Laravel handles and reports exceptions.
Laravel Pulse
Add a performance monitoring dashboard to your application.