Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pennant Laravel Package

laravel/pennant

Laravel Pennant is a simple, lightweight feature flag library for Laravel. Manage, evaluate, and roll out features safely across environments with an easy API and first-party integration, backed by official Laravel documentation.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require laravel/pennant
    php artisan pennant:install
    

    This publishes the migration and config file.

  2. Run Migration:

    php artisan migrate
    
  3. Define a Feature Flag:

    use Laravel\Pennant\Feature;
    
    Feature::create('new-dashboard', 'boolean', true);
    
  4. First Usage:

    if (Feature::get('new-dashboard')) {
        // Show new dashboard
    }
    

Where to Look First

  • Configuration: config/pennant.php (drivers, cache settings, default scope).
  • Facade: Feature facade for quick access.
  • Middleware: EnsureFeatureIsActive for route/endpoint protection.
  • Blade Directives: @feature and @featureany for view-level checks.

Implementation Patterns

Core Workflows

  1. Feature Flag Management:

    // Create a feature
    Feature::create('beta-invitations', 'boolean', false);
    
    // Toggle a feature
    Feature::set('beta-invitations', true);
    
    // Bulk updates
    Feature::setMany([
        'feature-a' => true,
        'feature-b' => false,
    ]);
    
  2. Scoped Features (e.g., per user/tenant):

    // Set scope (e.g., user ID)
    Feature::scope('user', auth()->id());
    
    // Check scoped feature
    if (Feature::get('premium-features')) {
        // Show premium content
    }
    
  3. Middleware Integration:

    Route::get('/admin', function () {
        // ...
    })->middleware('feature:admin-panel');
    

    Or globally for all routes:

    Feature::middleware(['admin-panel', 'beta-features']);
    
  4. Blade Directives:

    @feature('new-ui')
        <div>New UI Content</div>
    @endif
    
    @featureany(['experimental-a', 'experimental-b'])
        <div>Experimental Features</div>
    @endfeatureany
    
  5. Events & Hooks:

    // Listen for feature updates
    Feature::updated(function ($feature) {
        Log::info("Feature {$feature->name} updated to {$feature->value}");
    });
    
    // Use before hooks (e.g., for validation)
    Feature::before('payment-gateway', function () {
        return auth()->user()->hasRole('admin');
    });
    

Integration Tips

  • Cache Optimization: Use Feature::flushCache() after bulk updates or config changes.
  • Testing: Mock the Feature facade or use Feature::fake() for isolated tests.
  • Database Drivers: Supports database, cache, and custom drivers. Configure in config/pennant.php.
  • Laravel Mixins: Extend the Feature facade with custom methods:
    Feature::macro('isEnabledForUser', function ($user, $featureName) {
        return Feature::scope('user', $user->id)->get($featureName);
    });
    

Gotchas and Tips

Pitfalls

  1. Scope Leaks:

    • Scopes are not automatically reset. Always explicitly clear them:
      Feature::scope('user', $userId);
      // ... logic ...
      Feature::scope(null); // Reset scope
      
    • Use Feature::defaultScope() to avoid hardcoding scopes.
  2. Cache Invalidation:

    • After manual database updates (e.g., via raw SQL), call Feature::flushCache().
    • Configure cache_flush_after_write in config/pennant.php to auto-flush on writes.
  3. Type Safety:

    • Features with custom classes (e.g., Feature::create('user-role', UserRole::class)) require proper serialization.
    • Use Feature::resolve() to get typed instances:
      $role = Feature::resolve('user-role');
      
  4. Middleware Conflicts:

    • The EnsureFeatureIsActive middleware throws a 403 by default. Customize the response in your middleware:
      public function handle($request, Closure $next, $feature)
      {
          if (!Feature::get($feature)) {
              abort(404); // Or redirect()
          }
          return $next($request);
      }
      
  5. Bulk Operations:

    • Avoid Feature::setMany() in loops. Batch updates for performance:
      Feature::setMany($features); // Single DB query
      

Debugging Tips

  • Check Feature Existence:
    if (Feature::has('non-existent-feature')) {
        // ...
    }
    
  • Inspect Scopes:
    dd(Feature::scopes()); // Shows current scopes
    
  • Log Feature Values:
    Feature::updated(function ($feature) {
        Log::debug("Feature {$feature->name} set to {$feature->value}");
    });
    

Extension Points

  1. Custom Drivers:

    • Implement Laravel\Pennant\Contracts\Driver for non-DB storage (e.g., Redis, S3).
    • Register in config/pennant.php:
      'driver' => \App\Pennant\Drivers\CustomDriver::class,
      
  2. Decorators:

    • Extend Laravel\Pennant\Decorators\Decorator to add logic (e.g., A/B testing):
      Feature::decorate(function ($feature) {
          if ($feature->name === 'ab-test') {
              return Feature::get('ab-test') === 'variant-b';
          }
          return $feature->value;
      });
      
  3. Events:

    • Listen for FeatureUpdated, FeaturesPurged, or FeatureCreated events for analytics/auditing.
  4. Blade Extensions:

    • Override directives in a service provider:
      Blade::directive('feature', function ($expression) {
          return "<?php if (\\Laravel\\Pennant\\Feature::get({$expression})): ?>";
      });
      

Performance Quirks

  • Database Driver: Use loadAll() to preload features for a scope (reduces N+1 queries).
  • Cache Driver: Disable cache_flush_after_write if using a fast cache (e.g., Redis) and manually flush when needed.
  • High Traffic: For write-heavy apps, consider the unique constraint improvements in v1.8.0 to avoid deadlocks.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope