PHPackages                             e0ipso/feature\_flags - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. e0ipso/feature\_flags

ActiveDrupal-module

e0ipso/feature\_flags
=====================

A module for feature flags in Drupal.

v1.1.4(1mo ago)1698↑16.7%1GPL-2.0-or-laterPHPCI passing

Since Dec 13Pushed 4mo agoCompare

[ Source](https://github.com/e0ipso/feature_flags)[ Packagist](https://packagist.org/packages/e0ipso/feature_flags)[ RSS](/packages/e0ipso-feature-flags/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (10)Versions (11)Used By (0)

Feature Flags
=============

[](#feature-flags)

**Client-side feature flags that work with Varnish, CDN, and BigPipe. Resolve variants in JavaScript, not PHP.**

[![Drupal](https://camo.githubusercontent.com/a7524e87505d3a3f70fdc54852cc8dcd3b5014c25a8cbf99621c722ce6a50714/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64727570616c2d31302e7825323025374325323031312e782d626c7565)](https://camo.githubusercontent.com/a7524e87505d3a3f70fdc54852cc8dcd3b5014c25a8cbf99621c722ce6a50714/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64727570616c2d31302e7825323025374325323031312e782d626c7565) [![PHP](https://camo.githubusercontent.com/344e820b219cee3234648531306104364bd684892ad13c5dc79e66eb82a15b90/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e322532422d626c7565)](https://camo.githubusercontent.com/344e820b219cee3234648531306104364bd684892ad13c5dc79e66eb82a15b90/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e322532422d626c7565)

---

What This Module Does
---------------------

[](#what-this-module-does)

Create feature flags with multiple variants. Configure percentage rollouts and conditions. Everything resolves **client-side** so your page cache stays fast.

Perfect for high-traffic sites using aggressive caching (Varnish, CDN, BigPipe).

**Pairs beautifully with [ab\_tests](https://github.com/Lullabot/ab_tests) for A/B testing with metrics.**

---

See It In Action
----------------

[](#see-it-in-action)

### Video Walkthrough

[](#video-walkthrough)

    coin-flip-demo.webm    👆 30-second walkthrough showing the complete setup and resolution process

### Step-by-Step with Screenshots

[](#step-by-step-with-screenshots)

#### 1. Enable Settings (Debug + Persistence)

[](#1-enable-settings-debug--persistence)

[![Settings Page](docs/images/settings.png)](docs/images/settings.png)

Enable debug mode to see resolution in console. Enable persistence to cache decisions in localStorage.

#### 2. Create Your Feature Flag

[](#2-create-your-feature-flag)

[![Create Flag](docs/images/create-flag.png)](docs/images/create-flag.png)

Define basic info: label, machine name, description.

#### 3. Add Variants (Minimum 2, JSON Values)

[](#3-add-variants-minimum-2-json-values)

[![Variants](docs/images/variants.png)](docs/images/variants.png)

Each variant has a label and JSON value. CodeMirror editor included.

**Example: "Heads, Tails, or Edge" coin flip**

- **Heads**: `{"result": "heads", "color": "#FFD700"}`
- **Tails**: `{"result": "tails", "color": "#C0C0C0"}`
- **Edge**: `{"result": "edge", "color": "#FF6B6B"}` (rare!)

#### 4. Configure Percentage Rollout

[](#4-configure-percentage-rollout)

[![Algorithms](docs/images/algorithms.png)](docs/images/algorithms.png)

48% Heads, 48% Tails, 4% Edge. Percentages must sum to 100%.

#### 5. Resolve in JavaScript

[](#5-resolve-in-javascript)

```
const result = await Drupal.featureFlags.resolve('coin_flip');

console.log(result.result);
// { result: "heads", color: "#FFD700" }

console.log(result.variant.label);
// "Heads"
```

**Console Output:**

[![Console Resolution](docs/images/console.png)](docs/images/console.png)

Debug mode shows the full resolution process. Result is cached in localStorage for consistency.

---

Installation
------------

[](#installation)

```
composer require e0ipso/feature_flags
drush pm:enable feature_flags -y
```

---

Core Concepts
-------------

[](#core-concepts)

### Variants

[](#variants)

Each flag has **2 or more variants** with JSON values. Think of variants as the possible outcomes.

```
{"enabled": true, "theme": "dark"}
{"enabled": false, "theme": "light"}
```

### Algorithms

[](#algorithms)

Algorithms decide which variant a user gets. The **Percentage Rollout** algorithm distributes users by percentage (e.g., 25% variant A, 75% variant B).

**How to create a custom algorithm**1. **PHP Plugin**: `src/Plugin/DecisionAlgorithm/MyAlgorithm.php`

    - Extends `DecisionAlgorithmPluginBase`
    - Defines admin configuration form
    - Returns JavaScript settings
2. **JavaScript Class**: `js/algorithm/MyAlgorithm.js`

    - Extends `BaseAlgorithm`
    - Implements `decide(context)` method
    - Returns selected variant
3. **Library**: Add to `feature_flags.libraries.yml`

```
/**
 * @DecisionAlgorithm(
 *   id = "my_algorithm",
 *   label = @Translation("My Custom Algorithm"),
 *   js_library = "feature_flags/algorithm.my_algorithm",
 *   js_class = "MyAlgorithm"
 * )
 */
class MyAlgorithm extends DecisionAlgorithmPluginBase {
  public function decide(array $context): Variant {
    // Your logic here
    return $selectedVariant;
  }
}
```

```
// js/algorithm/MyAlgorithm.js
class MyAlgorithm extends Drupal.featureFlags.BaseAlgorithm {
  decide(context) {
    // Your client-side logic
    return this.featureFlag.variants[0];
  }
}
```

### Conditions

[](#conditions)

Conditions filter **when** an algorithm applies. Target specific users, or custom context.

**Built-in conditions:**

- **User ID**: Match specific user IDs

**How to provide custom context**Listen to the `featureFlags:provideContext` event:

```
document.addEventListener('featureFlags:provideContext', (event) => {
  // Add your custom context
  event.detail.addContext('user_tier', drupalSettings.user.tier);
  event.detail.addContext('region', 'US-West');
  event.detail.addContext('subscription_level', 'premium');

  // Async context supported
  event.detail.addContext('features', await fetchUserFeatures());
});
```

Then create conditions that evaluate your custom context:

```
/**
 * @AlgorithmCondition(
 *   id = "region",
 *   label = @Translation("Region"),
 *   context_key = "region"
 * )
 */
class RegionCondition extends AlgorithmConditionPluginBase {
  public function evaluate(array $context): bool {
    return in_array($context['region'] ?? '', $this->configuration['allowed_regions']);
  }
}
```

---

Use With ab\_tests for A/B Testing
----------------------------------

[](#use-with-ab_tests-for-ab-testing)

The `feature_flags` module controls **rollout**. The [`ab_tests` module](https://github.com/Lullabot/ab_tests) tracks **metrics**.

**Example: Progressive checkout rollout with conversion tracking**

```
// 1. Resolve which checkout version to show
const checkout = await Drupal.featureFlags.resolve('new_checkout');

if (checkout.result.enabled) {
  // 2. Show new checkout
  loadNewCheckout();

  // 3. Track experiment with ab_tests
  Drupal.behaviors.abTests.trackExperiment('checkout_test', {
    variant: checkout.variant.label,
    user_id: drupalSettings.user.uid,
  });

  // 4. Track conversion on purchase
  document.querySelector('.purchase-button').addEventListener('click', () => {
    Drupal.behaviors.abTests.trackConversion('checkout_test', 'purchase');
  });
}
```

**When to use each:**

NeedUseWhyGradual rollout (10% → 50% → 100%)`feature_flags`Percentage controlTrack metrics &amp; conversions`ab_tests`AnalyticsExperiment + rollout**Both together**Best of both worlds---

Requirements
------------

[](#requirements)

- Drupal 10.3+ or 11.x
- PHP 8.2+
- Modern browser with ES6 support

---

Testing
-------

[](#testing)

**Test Commands**```
# PHP tests
vendor/bin/phpunit web/modules/contrib/feature_flags

# JavaScript tests
cd web/modules/contrib/feature_flags
npm test

# E2E tests
npm run e2e:test

# Code quality
vendor/bin/phpstan analyse web/modules/contrib/feature_flags
vendor/bin/phpcs --standard=Drupal web/modules/contrib/feature_flags
npm run js:check
```

---

Documentation
-------------

[](#documentation)

- [docs/diagrams.md](docs/diagrams.md) - Mermaid diagram source code

---

License
-------

[](#license)

GPL v2 or later

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance81

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 99.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Recently: every ~23 days

Total

9

Last Release

52d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1140906?v=4)[Mateu Aguiló Bosch](/maintainers/e0ipso)[@e0ipso](https://github.com/e0ipso)

---

Top Contributors

[![e0ipso](https://avatars.githubusercontent.com/u/1140906?v=4)](https://github.com/e0ipso "e0ipso (245 commits)")[![deviantintegral](https://avatars.githubusercontent.com/u/255023?v=4)](https://github.com/deviantintegral "deviantintegral (1 commits)")

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/e0ipso-feature-flags/health.svg)

```
[![Health](https://phpackages.com/badges/e0ipso-feature-flags/health.svg)](https://phpackages.com/packages/e0ipso-feature-flags)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
