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

Feature Flags Laravel Package

ylsideas/feature-flags

Extendable Laravel feature flags (toggles) to safely gate code and support continuous delivery. Use flags across your app, including routes, Blade views, task scheduling, and validation—built for flexibility and easy integration.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require ylsideas/feature-flags:^3.0
   php artisan vendor:publish --provider="YlsIdeas\FeatureFlags\FeatureFlagsServiceProvider" --tag=config
  • Publishes config/features.php for customization.
  1. First Check:

    use YlsIdeas\FeatureFlags\Facades\Features;
    
    if (Features::accessible('new-dashboard')) {
        // Enable new dashboard logic
    }
    
  2. Default Configuration:

    • Uses in_memory driver by default (stored in config/features.php).
    • Supports multiple drivers (e.g., cache, database, gates) via pipeline.

First Use Case: Route Protection

Route::get('/admin', function () {
    return view('admin.dashboard');
})->middleware('feature:admin-panel');
  • Requires FeatureMiddleware (auto-registered) and configures admin-panel flag in features.php.

Implementation Patterns

1. Core Workflows

Basic Flag Checks

// Direct check
if (Features::accessible('experimental-api')) {
    // Enable API
}

// Negated check
if (!Features::accessible('legacy-system')) {
    // Disable legacy code
}

Contextual Access

// User-specific flags (via gates)
Features::accessible('premium-feature', user: auth()->user());

// Role-based flags
Features::accessible('admin-only', role: 'admin');

Dynamic Flag Evaluation

// Combine multiple flags (AND/OR logic)
Features::accessible(['flag1', 'flag2']); // AND
Features::accessible(['flag1', 'flag2'], mode: 'or'); // OR

2. Integration Patterns

Middleware Integration

// In `app/Http/Kernel.php`
protected $routeMiddleware = [
    'feature' => \YlsIdeas\FeatureFlags\Http\Middleware\FeatureMiddleware::class,
];

// Usage in routes
Route::get('/beta', function () {})->middleware('feature:beta-feature');

Query Builder Mixins

// Enable queries only if flag is on
User::whenFeatureIsAccessible('new-users-table')
    ->where('active', true)
    ->get();

// Exclude queries if flag is off
User::whenFeatureIsNotAccessible('old-users-table')
    ->where('active', true)
    ->get();

Validation Rules

use YlsIdeas\FeatureFlags\Rules\FeatureFlag;

$request->validate([
    'field' => ['required', new FeatureFlag('required-field')],
]);

Task Scheduling

// In `app/Console/Kernel.php`
protected function schedule(Schedule $schedule)
{
    $schedule->command('backup:database')
        ->whenFeatureIsAccessible('auto-backup');
}

Blade Directives

@feature('new-ui')
    <div class="modern-ui">...</div>
@else
    <div class="legacy-ui">...</div>
@endfeature

3. Testing Patterns

Fake Flags in Tests

// Enable a flag for testing
Features::fake(['test-flag' => true]);

// Disable all flags
Features::fake([]);

// Assert flag state
Features::assertAccessible('test-flag');
Features::assertNotAccessible('disabled-flag');

Test Helpers

// Test a feature's accessibility
public function test_feature_flag()
{
    Features::fake(['test-flag' => true]);

    $this->assertTrue(Features::accessible('test-flag'));
}

4. Advanced Patterns

Custom Drivers

// Register a custom driver in `config/features.php`
'drivers' => [
    'custom' => \App\Services\CustomFeatureDriver::class,
],

// Implement `YlsIdeas\FeatureFlags\Contracts\FeatureFlagDriver`
class CustomFeatureDriver implements FeatureFlagDriver {
    public function accessible(string $name, array $context = []): bool
    {
        // Custom logic
    }
}

Pipeline Configuration

// Override default pipeline in `config/features.php`
'pipeline' => [
    'cache', // Cache layer
    'database', // Persistent storage
    'gates', // Gate-based access
],

Feature Expiration

// Set expiration in config
'flags' => [
    'limited-offer' => [
        'expires' => now()->addDays(30),
    ],
],

// Handle expiration via event
event(new \YlsIdeas\FeatureFlags\Events\FeatureExpired('limited-offer'));

Gotchas and Tips

Common Pitfalls

  1. Cache Invalidation:

    • Flags cached via cache driver require manual cache clearing:
      php artisan cache:clear
      
    • Use Features::clearCache() programmatically if needed.
  2. Middleware Messages:

    • Customize redirect messages in config/features.php:
      'middleware' => [
          'message' => 'This feature is not available yet. Please try again later.',
      ],
      
  3. Driver Order Matters:

    • Pipeline drivers execute in order. Place gates last for role-based overrides.
  4. Boolean Casting:

    • Ensure cached results are cast to boolean (fixed in v3.0.1). Avoid:
      if (Features::accessible('flag') == 'true') { // ❌ Avoid string comparison
      
  5. Maintenance Mode:

    • Flags respect Laravel’s maintenance mode. Disable flags during maintenance:
      if (app()->isDownForMaintenance()) {
          Features::fake([]);
      }
      

Debugging Tips

  1. Debug Accessed Flags:

    • Enable debug mode in config/features.php:
      'debug' => env('APP_DEBUG', false),
      
    • Logs all flag accesses to storage/logs/laravel.log.
  2. State Inspection:

    • Use the feature:state Artisan command:
      php artisan feature:state
      
    • List all flags and their current state.
  3. Fake Overrides:

    • Fakes stack multiplicatively. Clear fakes between tests:
      Features::fake(['flag1' => true]);
      Features::fake(['flag2' => true]); // Overrides flag1
      Features::clearFakes(); // Reset
      

Performance Tips

  1. Cache Layer:

    • Use cache driver for high-traffic flags:
      'drivers' => [
          'cache' => [
              'driver' => 'redis',
              'prefix' => 'feature_flags_',
          ],
      ],
      
  2. In-Memory Driver:

    • Avoid in_memory for production (resets on app restart).
  3. Query Builder:

    • Prefer whenFeatureIsAccessible() over where() for dynamic queries to avoid N+1 issues.

Extension Points

  1. Custom Context Handlers:

    • Extend YlsIdeas\FeatureFlags\Contracts\ContextHandler for custom logic (e.g., IP-based flags).
  2. Event Listeners:

    • Listen for FeatureAccessed events:
      event(new \YlsIdeas\FeatureFlags\Events\FeatureAccessed('flag-name', $context));
      
  3. IDE Support:

    • Install barryvdh/laravel-ide-helper for autocompletion:
      composer require barryvdh/laravel-ide-helper
      php artisan ide-helper:generate
      
  4. Flagfox Dashboard:

    • Integrate Flagfox for UI management (waitlist required).

Configuration Quirks

  1. Default Flags:

    • Define defaults in config/features.php:
      'flags' => [
          'new-checkout' => true,
          'experimental-api' => false,
      ],
      
  2. Environment Overrides:

    • Override flags per environment:
      'flags' => [
          'staging-only' => env('APP_ENV') === 'staging',
      ],
      
  3. Pipeline Shortcuts:

    • Use null to skip a driver in the pipeline:
      'pipeline' => [null, 'database'], // Skip first driver
      

Migration Tips

  1. From v1 to v2:

    • Update config/features.php to use in_memory driver.
    • Replace Features::repository() with Features::accessible().
  2. From v2 to v3:

    • No breaking changes, but leverage new Laravel 12+ features (e.g., whenFeatureIsAccessible()).
  3. Database Migration:

    • For database driver, create a feature_flags table:
      Schema::create('feature_flags',
      
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