laravel-runtime-feature maintained by al_imran
Laravel Runtime Feature
A high-performance, decoupled feature flag engine for Laravel. Dynamically control application behavior without code deployments.
Why this package?
- Zero-Dependency Core: Decoupled from Auth, User models, or external permissions.
- Dynamic Payloads: Return complex JSON configurations, not just booleans.
- Contextual Awareness: Evaluate flags based on Users, Requests, IPs, or any custom entity.
- Atomic Caching: Cache-first evaluation with automatic invalidation on updates.
- Management UI: Built-in sleek dashboard for real-time feature control.
Quick Start
1. Installation
composer require al_imran/laravel-runtime-feature
2. Setup
Run the following command to publish assets and handle migrations:
php artisan feature:install
This command will:
- Publish the configuration file.
- Publish the database migrations.
- Ask to run migrations automatically.
1. Simple On/Off Checks (enabled)
Use this when you just need to know if a feature is active.
use Imran\LaravelRuntimeFeature\Facades\Feature;
// Returns true if 'new_ui' is enabled in the dashboard
if (Feature::enabled('new_ui')) {
// Show the new UI
}
2. Configuration Values (value)
Use this to retrieve dynamic data (numbers, strings, or arrays) stored inside a feature.
// If 'upload_limit' exists, it returns its value.
// If it doesn't exist, it returns the default (50).
$limit = feature('upload_limit')->value(50);
Quick Reference
| Method | Returns | Use Case |
|---|---|---|
enabled() |
true / false |
Is the light switch ON? |
value() |
mixed data |
How BRIGHT is the light? |
Practical Examples
Here is how you would typically interact with a feature named test_access:
// 1. Check if the feature is enabled for the current user
if (feature('test_access')->enabled()) {
// Current user has access to the test feature
}
// 2. Get the specific value/configuration stored in the feature
// If the feature stores {"role": "admin", "beta_group": 1}
$config = feature('test_access')->value();
echo $config['role']; // Output: admin
// Using the Facade instead of the helper
use Imran\LaravelRuntimeFeature\Facades\Feature;
if (Feature::enabled('test_access')) {
$value = Feature::value('test_access');
}
Contextual Evaluation
Pass any object or value to evaluate dynamic rules (e.g., target specific users or plans).
// Explicit context
if (Feature::enabled('beta_access', $user)) {
// ...
}
// Dynamic payload based on context
$discount = feature('holiday_sale')->value(['percent' => 5], $user);
Middleware Protection
Route::middleware('feature:premium_search')->group(function () {
Route::get('/search/advanced', [SearchController::class, 'advanced']);
});
Extending the Engine
Custom Conditions
Create a class implementing FeatureCondition to define your own logic.
namespace App\Features\Conditions;
use Imran\LaravelRuntimeFeature\Contracts\FeatureCondition;
class SubscriptionPlanCondition implements FeatureCondition
{
/**
* @param mixed $context Usually the User model
* @param mixed $value The value defined in the rule (e.g., 'pro')
*/
public function passes($context, $value): bool
{
return $context && $context->plan === $value;
}
}
Register it in your AppServiceProvider:
Feature::extend('plan', SubscriptionPlanCondition::class);
Testing & Quality Assurance
Suggested Test Cases for Developers
When implementing feature flags, ensure your test suite covers these scenarios:
- Default Fallback: Verify the application behaves correctly when a feature flag is missing from the database.
- Toggle Consistency: Assert that functionality disappears immediately when
enabledis set tofalse. - JSON Schema Integrity: If using JSON values, test that your code handles missing keys or malformed data gracefully.
- Context Leakage: Ensure
User A(with feature) andUser B(without) see different results in the same request cycle. - Cache Invalidation: Verify that updating a feature via the UI/Database reflects in the application without manual cache clears.
Mocking in Tests
public function test_premium_feature_is_accessible()
{
Feature::fake(['premium_access' => true]);
$response = $this->get('/premium-zone');
$response->assertStatus(200);
}
Management Dashboard
Access the built-in manager at /features-manager.
Note on Routes: Routes are loaded automatically from the package. If you need to customize the URLs or middleware, you can publish the route file manually:
php artisan vendor:publish --tag=feature-routes
Once published, Laravel will use routes/runtimeFeature.php instead of the package's internal file.
Features include:
- Real-time toggle of flags.
- JSON payload editor with validation.
- Cache invalidation tracking.
[!IMPORTANT] Secure this route in production by defining custom middleware in
config/feature.php.
Uninstallation
To cleanly remove the package and all its data (tables, config, and migrations), run:
php artisan feature:uninstall
After the cleanup command finishes, you can remove the package via composer:
composer remove al_imran/laravel-runtime-feature
License
The MIT License (MIT).