Skip to main content

Qué es Laravel Pennant

Laravel Pennant es un paquete ligero y sencillo para gestionar feature flags. Con ellos puedes desplegar nuevas funcionalidades de forma progresiva, realizar tests A/B o complementar el desarrollo trunk-based.

Qué son las feature flags

Las feature flags separan el despliegue del código de su lanzamiento. Puedes desplegar el código en producción y activar o desactivar la funcionalidad únicamente mediante configuración.

Instalación

1

Instalar el paquete

Instala Pennant con Composer.
2

Publicar la configuración y las migraciones

Publica los archivos con el comando Artisan vendor:publish.
Se generan config/pennant.php y las migraciones en database/migrations.
3

Ejecutar las migraciones

Se crea la tabla features, en la que Pennant guarda los valores de las feature flags.

Configuración

En config/pennant.php configuras el driver de almacenamiento. Pennant admite dos drivers:

Definir features

Definición basada en closure

Define las features con el método define del facade Feature. Habitualmente se hace en el boot de un service provider. La closure recibe un «scope» (por defecto, el usuario autenticado).
Lógica de la feature del ejemplo:
  • Los miembros del equipo interno la tienen siempre ON.
  • Los clientes de alto tráfico la tienen OFF.
  • El resto tienen un 1 % de probabilidad de tenerla ON.
La primera vez que se comprueba la feature se persiste el resultado de la closure. Las siguientes veces se utiliza el valor almacenado.
Si la definición solo devuelve una Lottery, puedes omitir la closure.

Definición basada en clase

Pennant también permite definir features como clase. No es necesario registrarlas en el service provider.
La clase generada se ubica en app/Features. Basta con implementar el método resolve.

Personalizar el nombre almacenado

Por defecto se guarda el nombre de clase totalmente cualificado. Puedes personalizarlo con el atributo Name.

Interceptar la comprobación con before

En las features basadas en clase puedes definir el método before. Se ejecuta en memoria antes de acudir al almacenamiento; si devuelve un valor distinto de null, ese será el resultado.
before resulta útil para desactivar una feature de emergencia ante un bug o para programar un lanzamiento a una fecha concreta.

Comprobar features

Feature::active() / Feature::inactive()

Con active compruebas si la feature está activa. Por defecto se comprueba contra el usuario autenticado.
En features basadas en clase pasa el nombre de la clase.
Otros métodos útiles:

Ejecución condicional (when / unless)

Con when ejecutas una closure solo si la feature está activa.
unless hace lo contrario: ejecuta la primera closure cuando la feature está inactiva.

Trait HasFeatures

Añadiendo HasFeatures al modelo User, puedes comprobar features directamente desde el modelo.

Directivas Blade

En las plantillas Blade dispones de la directiva @feature.

Middleware

El middleware EnsureFeaturesAreActive indica que una ruta requiere una feature activa. Si no lo está, devuelve 400 Bad Request.
Con whenInactive puedes personalizar la respuesta.

Caché en memoria

Dentro de una misma petición, Pennant cachea en memoria los resultados de las features. Comprobar la misma flag varias veces no genera consultas adicionales. Para vaciar la caché manualmente utiliza flushCache.

Scopes

Indicar el scope

Por defecto el scope es el usuario autenticado, pero puedes indicar cualquier otro con for.
Ejemplo de gestión por equipo:

Personalizar el scope por defecto

Con Feature::resolveScopeUsing puedes personalizar el scope por defecto.
Después, si omites for, se usa el scope por defecto.

Scope opcional (nullable)

Cuando el scope es null (rutas sin autenticación, comandos Artisan…), si la definición no lo admite se devuelve automáticamente false. Si necesitas gestionar el caso null, tipa el argumento como nullable.

Valores enriquecidos

Las features pueden devolver valores distintos de un booleano. Por ejemplo, para controlar el color de un botón en un test A/B.
Para obtener el valor utiliza value.
En Blade puedes ramificar por valor.
Cuando se usan valores enriquecidos, cualquier valor distinto de false se considera activo.
Si el valor enriquecido se pasa a when, la primera closure recibe dicho valor.

Obtener varias features

Con values puedes obtener varios valores a la vez.
Con all obtienes el valor de todas las features definidas.
Para incluir las features basadas en clase en el resultado de all, llama a discover en un service provider.
Con eso se registran todas las clases del directorio app/Features.

Eager loading

Si compruebas features dentro de un bucle pueden aparecer problemas de rendimiento. Con load puedes precargar los valores.
Para cargar solo lo que aún no está cargado, utiliza loadMissing.

Actualizar valores

Actualización manual

activate y deactivate cambian el estado ON/OFF.
Para olvidar el valor almacenado utiliza forget. La próxima comprobación reevaluará la definición.

Actualización masiva

activateForEveryone y deactivateForEveryone aplican el valor a todos los scopes almacenados.

Purgar features

Si eliminas o cambias una feature, puedes borrar los valores del almacenamiento con purge.
También puedes hacerlo desde Artisan, ideal para integrarlo en la pipeline de despliegue.

Tests

Redefinir features

En los tests puedes controlar el valor devuelto redefiniendo la feature con Feature::define.
tab=Pest
tab=PHPUnit
Lo mismo con features basadas en clase.
tab=Pest
tab=PHPUnit

Configurar el store para pruebas

Puedes indicar el store con una variable de entorno en phpunit.xml.

Drivers personalizados

Si los drivers integrados no cumplen tus necesidades, puedes crear uno personalizado implementando Laravel\Pennant\Contracts\Driver.
Regístralo con extend en el método boot de un service provider.
Después indícalo en config/pennant.php.

Resumen

Próximos pasos

Debug y gestión de errores

Aprende cómo maneja Laravel las excepciones y los informes de errores.

Laravel Pulse

Añade a tu aplicación un panel de monitorización de rendimiento.
Última modificación el 13 de julio de 2026