Home PHP Laravel Pulse & Pennant: Monitor & Feature Flags in Production
Intermediate 3 min · July 13, 2026

Laravel Pulse & Pennant: Monitor & Feature Flags in Production

Learn to monitor Laravel apps with Pulse and manage feature flags with Pennant.

N
Naren Founder & Principal Engineer

20+ years shipping production PHP systems at scale. Everything here is grounded in real deployments.

Follow
Production
production tested
July 13, 2026
last updated
2,073
articles · all by Naren
Before you start⏱ 20-25 min read
  • Basic knowledge of Laravel (routes, controllers, Blade)
  • PHP 8.1+
  • Laravel 10.x or 11.x
  • Composer installed
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Laravel Pulse provides real-time monitoring for queues, requests, and more.
  • Laravel Pennant simplifies feature flag management with database or array drivers.
  • Both are first-party packages for production-grade apps.
  • Pulse helps identify bottlenecks; Pennant enables gradual rollouts.
  • Use Pulse's dashboard and Pennant's Blade directive for easy integration.
✦ Definition~90s read
What is Laravel Pulse and Pennant?

Laravel Pulse is a real-time monitoring dashboard for your application, and Pennant is a feature flag management package that lets you gradually roll out new features.

Think of Pulse as a car's dashboard that shows speed, fuel, and engine health—it helps you spot problems before they break down.
Plain-English First

Think of Pulse as a car's dashboard that shows speed, fuel, and engine health—it helps you spot problems before they break down. Pennant is like a light switch for new features: you can turn them on for a few users first, then everyone, without redeploying.

Building a Laravel application is exciting, but running it in production brings challenges: slow responses, queue failures, and risky feature rollouts. Laravel Pulse and Pennant are two first-party packages that address these pain points. Pulse gives you a real-time dashboard to monitor your app's health—request rates, queue throughput, slow queries, and more. Pennant lets you manage feature flags, enabling you to gradually release features to subsets of users without deploying new code. In this tutorial, you'll learn to install and configure both packages, write custom monitors, and use feature flags in controllers and Blade templates. We'll also cover a real-world production incident where Pulse caught a memory leak and Pennant saved a rollout. By the end, you'll be equipped to monitor and control your Laravel app like a pro.

Installing and Configuring Laravel Pulse

Laravel Pulse is a real-time monitoring package. Install it via Composer: composer require laravel/pulse. Then publish the config and migrations: php artisan vendor:publish --provider="Laravel\Pulse\PulseServiceProvider". Run migrations: php artisan migrate. Pulse uses a separate queue connection named 'pulse' to avoid interfering with your main queue. Configure it in config/queue.php:

``php 'connections' => [ 'pulse' => [ 'driver' => 'database', 'table' => 'pulse_jobs', 'queue' => 'default', 'retry_after' => 90, ], ], ``

Then set PULSE_QUEUE_CONNECTION=pulse in your .env. Finally, start the Pulse worker: php artisan pulse:check. Access the dashboard at /pulse (ensure the route is registered in routes/web.php).

config/pulse.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

return [
    'domain' => env('PULSE_DOMAIN'),
    'path' => env('PULSE_PATH', 'pulse'),
    'middleware' => ['web'],
    'recorders' => [
        \Laravel\Pulse\Recorders\CacheInteractions::class => [
            'enabled' => env('PULSE_CACHE_INTERACTIONS_ENABLED', true),
        ],
        \Laravel\Pulse\Recorders\Queues::class => [
            'enabled' => env('PULSE_QUEUES_ENABLED', true),
        ],
        \Laravel\Pulse\Recorders\SlowJobs::class => [
            'enabled' => env('PULSE_SLOW_JOBS_ENABLED', true),
            'threshold' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
        ],
        \Laravel\Pulse\Recorders\SlowOutgoingRequests::class => [
            'enabled' => env('PULSE_SLOW_OUTGOING_REQUESTS_ENABLED', true),
            'threshold' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
        ],
        \Laravel\Pulse\Recorders\SlowQueries::class => [
            'enabled' => env('PULSE_SLOW_QUERIES_ENABLED', true),
            'threshold' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
        ],
        \Laravel\Pulse\Recorders\Requests::class => [
            'enabled' => env('PULSE_REQUESTS_ENABLED', true),
            'threshold' => env('PULSE_REQUESTS_THRESHOLD', 1000),
        ],
    ],
];
💡Pulse Worker
📊 Production Insight
In production, ensure the Pulse worker has enough memory. Set memory_limit in php.ini to at least 128MB.
🎯 Key Takeaway
Install Pulse, configure its queue connection, and run the worker to start monitoring.

Custom Pulse Recorders

You can create custom recorders to monitor specific metrics. For example, monitor the number of failed login attempts. Create a recorder class that implements Laravel\Pulse\Recorders\Concerns\Ignores and uses the Laravel\Pulse\Recorders\Concerns\Sampling trait. Register it in config/pulse.php under recorders. Here's an example:

```php namespace App\Pulse;

use Laravel\Pulse\Recorders\Concerns\Ignores; use Laravel\Pulse\Recorders\Concerns\Sampling; use Laravel\Pulse\Pulse;

class FailedLogins { use Ignores, Sampling;

public function __construct(protected Pulse $pulse) { // }

public function register(): void { $this->pulse->event('failed_login', function () { // Increment counter $this->pulse->increment('failed_login_count'); }); } } ```

Then in AppServiceProvider::boot(), listen to the event and call the recorder. Pulse will display the metric on the dashboard if you create a custom card.

app/Pulse/FailedLogins.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

namespace App\Pulse;

use Laravel\Pulse\Pulse;
use Laravel\Pulse\Recorders\Concerns\Ignores;
use Laravel\Pulse\Recorders\Concerns\Sampling;

class FailedLogins
{
    use Ignores, Sampling;

    public function __construct(protected Pulse $pulse)
    {
        //
    }

    public function register(): void
    {
        $this->pulse->event('failed_login', function () {
            $this->pulse->increment('failed_login_count');
        });
    }
}
🔥Custom Cards
📊 Production Insight
Be careful with sampling rates to avoid performance overhead. Use the Sampling trait to record only a percentage of events.
🎯 Key Takeaway
Custom recorders let you monitor business-specific metrics like failed logins or signups.

Installing and Configuring Laravel Pennant

Laravel Pennant manages feature flags. Install: composer require laravel/pennant. Publish config: php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider". Run migrations: php artisan migrate. Define features in App\Features class. Example:

```php namespace App\Features;

use Laravel\Pennant\Feature;

class NewCheckout { public function resolve(User $user): bool { return $user->id <= 100; // Roll out to first 100 users } } ```

```php use App\Features\NewCheckout; use Laravel\Pennant\Feature;

if (Feature::active(NewCheckout::class)) { // new checkout logic } ```

``blade @feature('new-checkout') <p>New checkout experience</p> @endfeature ``

``php Feature::for($user)->active('new-checkout'); ``

app/Features/NewCheckout.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace App\Features;

use App\Models\User;
use Laravel\Pennant\Feature;

class NewCheckout
{
    public function resolve(User $user): bool
    {
        return $user->id <= 100;
    }

    public function description(): string
    {
        return 'New checkout flow with one-page payment';
    }
}
⚠ Cache Feature Flags
📊 Production Insight
Always cache feature flags in production. Use the pennant:cache command and clear cache when flags change.
🎯 Key Takeaway
Pennant makes it easy to define and check feature flags with scopes and Blade directives.

Advanced Pennant: Percentage Rollouts and A/B Testing

Pennant supports percentage-based rollouts and A/B testing. Use the percentage method:

``php Feature::define('new-checkout', function (User $user) { return Feature::percentage(50); // 50% of users }); ``

For A/B testing, use Feature::for($user)->active('new-checkout') and track conversions. You can also use the Feature::when method to execute code conditionally:

``php Feature::when('new-checkout', function () { // new checkout }, function () { // old checkout }); ``

You can also use database-driven flags by storing resolutions in the pennant_features table. Use the Laravel\Pennant\Drivers\DatabaseDriver driver in config/pennant.php:

``php 'driver' => env('PENNANT_DRIVER', 'database'), ``

Then manage flags via a UI or CLI.

routes/web.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
<?php

use Illuminate\Support\Facades\Route;
use Laravel\Pennant\Feature;

Route::get('/checkout', function () {
    return Feature::when('new-checkout', function () {
        return view('checkout.new');
    }, function () {
        return view('checkout.old');
    });
});
💡A/B Testing
📊 Production Insight
For large-scale A/B tests, use a dedicated database driver to avoid cache invalidation issues.
🎯 Key Takeaway
Percentage rollouts and A/B testing are straightforward with Pennant's built-in methods.

Integrating Pulse and Pennant: Monitoring Feature Flag Adoption

You can create a Pulse recorder to monitor how many users are seeing a feature flag. For example, track the number of times a feature is active:

```php namespace App\Pulse;

use Laravel\Pulse\Pulse;

class FeatureFlagUsage { public function __construct(protected Pulse $pulse) {}

public function register(): void { $this->pulse->event('feature_flag_checked', function (string $feature) { $this->pulse->increment('feature_flag_' . $feature); }); } } ```

```php use App\Pulse\FeatureFlagUsage; use Illuminate\Support\Facades\Event;

Event::dispatch('feature_flag_checked', 'new-checkout'); ```

This allows you to see adoption rates on the Pulse dashboard.

app/Providers/AppServiceProvider.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Pulse\Pulse;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->app->make(Pulse::class)->event('feature_flag_checked', function ($feature) {
            $this->app->make(Pulse::class)->increment('feature_flag_' . $feature);
        });
    }
}
🔥Combine Tools
📊 Production Insight
Monitor the database queries generated by Pennant's database driver to avoid N+1 issues.
🎯 Key Takeaway
Integrating Pulse and Pennant gives you visibility into feature adoption and performance.

Security Best Practices for Feature Flags

Feature flags can expose unfinished features. Always restrict access to authorized users. Use middleware to protect routes:

``php Route::middleware(['auth', 'feature:new-checkout'])->group(function () { Route::get('/checkout', [CheckoutController::class, 'index']); }); ``

```php namespace App\Http\Middleware;

use Closure; use Laravel\Pennant\Feature;

class EnsureFeatureIsActive { public function handle($request, Closure $next, $feature) { if (! Feature::active($feature)) { abort(404); } return $next($request); } } ```

Also, ensure that feature flag values are not exposed to the client side unless intended. Use environment-specific configurations and never hardcode sensitive flags.

app/Http/Middleware/EnsureFeatureIsActive.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

namespace App\Http\Middleware;

use Closure;
use Laravel\Pennant\Feature;

class EnsureFeatureIsActive
{
    public function handle($request, Closure $next, $feature)
    {
        if (! Feature::active($feature)) {
            abort(404);
        }
        return $next($request);
    }
}
⚠ Don't Expose Flags
📊 Production Insight
Use environment variables to control feature flags in different environments (dev, staging, production).
🎯 Key Takeaway
Secure feature flags with middleware and avoid exposing them to unauthorized users.
● Production incidentPOST-MORTEMseverity: high

The Silent Queue Failure: How Pulse Saved Our App

Symptom
Users reported orders taking hours to process, but no errors in logs.
Assumption
Developers assumed the queue worker was running fine because no exceptions were thrown.
Root cause
A memory leak in a job handler caused the worker to be killed by OOM killer, but Laravel's queue worker restarted silently, losing jobs.
Fix
Added Pulse's queue monitoring to alert on job failures and memory usage. Set memory limit in php.ini and refactored the job to release memory.
Key lesson
  • Monitor queue throughput and failure rates in production.
  • Set memory limits for queue workers.
  • Use Pulse to detect silent failures.
  • Always log job failures even if retried.
  • Implement health checks for critical background processes.
Production debug guideSymptom to Action4 entries
Symptom · 01
Pulse dashboard shows high slow query count
Fix
Identify the query via Pulse's 'Slow Queries' card. Use EXPLAIN to analyze. Add indexes or optimize the query.
Symptom · 02
Feature flag not working for a user
Fix
Check if the user is resolved correctly. Verify Pennant's storage driver (database or array). Clear cache with php artisan optimize:clear.
Symptom · 03
Pulse dashboard not updating
Fix
Ensure the Pulse worker is running (php artisan pulse:check). Check queue connection and supervisor configuration.
Symptom · 04
Pennant flag returns null unexpectedly
Fix
Verify the flag name and scope. Ensure the feature is defined in App\Features class. Check for typos.
★ Quick Debug Cheat SheetCommon issues and immediate actions for Pulse and Pennant.
Pulse dashboard blank
Immediate action
Check Pulse worker status
Commands
php artisan pulse:check
php artisan queue:work --queue=pulse
Fix now
Restart supervisor or run pulse:check manually
Feature flag not applying+
Immediate action
Clear config and cache
Commands
php artisan optimize:clear
php artisan pennant:cache
Fix now
Check feature definition in App\Features
High memory usage in Pulse+
Immediate action
Check for memory leaks in custom monitors
Commands
php artisan pulse:check --memory-limit=128
top -p $(pgrep -f 'pulse:check')
Fix now
Increase memory limit or optimize monitor
FeatureLaravel PulseLaravel Pennant
PurposeReal-time monitoringFeature flag management
Installationcomposer require laravel/pulsecomposer require laravel/pennant
Queue RequiredYes (separate queue)No
DashboardBuilt-in at /pulseNo built-in UI (manage via code/CLI)
Custom MetricsYes (custom recorders)N/A
CachingNot neededRecommended (pennant:cache)
Use CaseIdentify bottlenecksGradual rollouts
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
configpulse.phpreturn [Installing and Configuring Laravel Pulse
appPulseFailedLogins.phpnamespace App\Pulse;Custom Pulse Recorders
appFeaturesNewCheckout.phpnamespace App\Features;Installing and Configuring Laravel Pennant
routesweb.phpuse Illuminate\Support\Facades\Route;Advanced Pennant
appProvidersAppServiceProvider.phpnamespace App\Providers;Integrating Pulse and Pennant
appHttpMiddlewareEnsureFeatureIsActive.phpnamespace App\Http\Middleware;Security Best Practices for Feature Flags

Key takeaways

1
Laravel Pulse provides real-time monitoring with minimal setup.
2
Laravel Pennant enables safe feature rollouts with percentage and user-based scopes.
3
Combine both tools to monitor feature adoption and performance.
4
Always cache feature flags and run Pulse workers in production.
5
Secure feature flags with middleware and avoid exposing them to clients.

Common mistakes to avoid

4 patterns
×

Not running the Pulse worker in production

×

Hardcoding feature flag values in controllers

×

Forgetting to cache Pennant flags in production

×

Exposing feature flag states to the frontend without authentication

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the purpose of Laravel Pulse?
Q02SENIOR
How would you implement a percentage-based feature rollout with Pennant?
Q03SENIOR
How can you create a custom Pulse recorder to monitor failed login attem...
Q01 of 03JUNIOR

What is the purpose of Laravel Pulse?

ANSWER
Pulse provides real-time monitoring of application health, including request rates, queue throughput, slow queries, and more.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Can I use Pulse without a queue?
02
How do I reset a feature flag for a user?
03
Does Pulse support custom metrics?
04
Can I use Pennant with non-Laravel apps?
05
How do I monitor Pulse in a load-balanced environment?
N
Naren Founder & Principal Engineer

20+ years shipping production PHP systems at scale. Everything here is grounded in real deployments.

Follow
Verified
production tested
July 13, 2026
last updated
2,073
articles · all by Naren
🔥

That's Laravel. Mark it forged?

3 min read · try the examples if you haven't

Previous
Laravel Folio and Volt: File-Based Routing and Livewire Components
18 / 24 · Laravel
Next
Laravel Octane: High-Performance Application Serving