[ GUIDE ]

How to Monitor Laravel Cache in Production

Hit rates, latency, stampedes, and the events you can listen to right now.

QUICK ANSWER

How do I monitor Laravel cache in production?

Hook into CacheHit and CacheMissed events in AppServiceProvider to count hits vs misses, then aggregate by key pattern, not per-key. Track per-pattern hit rate and p95 latency. An APM with a cache watcher (NightOwl, Laravel Nightwatch Cloud) does this automatically across all traffic, including which routes miss which patterns most often.

Updated · 2026-04-13

Listen to cache events

Laravel fires events on every cache operation. Register listeners in AppServiceProvider::boot.

app/Providers/AppServiceProvider.phpphp
use Illuminate\Cache\Events\CacheHit;
use Illuminate\Cache\Events\CacheMissed;
use Illuminate\Cache\Events\KeyWritten;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(CacheHit::class, function (CacheHit $e) {
        // Group by pattern, not raw key — 'user:742' → 'user:?'
        $pattern = preg_replace('/:\d+/', ':?', $e->key);
        metrics()->increment('cache.hit', tags: ['pattern' => $pattern]);
    });

    Event::listen(CacheMissed::class, function (CacheMissed $e) {
        $pattern = preg_replace('/:\d+/', ':?', $e->key);
        metrics()->increment('cache.miss', tags: ['pattern' => $pattern]);
    });
}

Don't store raw keys. At scale, per-key metrics are unmanageable (millions of unique keys). Normalize to patterns and aggregate.

Prevent cache stampedes

A popular cached value expires. 100 requests simultaneously try to recompute it, all hitting the database. Your DB melts.

Stampede-prone — don't do this at scale

php
$value = Cache::remember('dashboard:stats', 300, function () {
    return DB::table('orders')->selectRaw('...')->get(); // expensive
});

Stampede-safe with atomic lock

php
$value = Cache::get('dashboard:stats');

if ($value === null) {
    $lock = Cache::lock('dashboard:stats:lock', 10);

    if ($lock->get()) {
        try {
            $value = DB::table('orders')->selectRaw('...')->get();
            Cache::put('dashboard:stats', $value, 300);
        } finally {
            $lock->release();
        }
    } else {
        // Another worker is recomputing — wait or fall back
        $value = Cache::get('dashboard:stats:stale') ?? [];
    }
}

Pick a shared cache store

Multi-server setups need a shared cache — file and database drivers are per-server and will cause hard-to-debug inconsistencies.

config/cache.phpphp
'default' => env('CACHE_STORE', 'redis'),

'stores' => [
    'redis' => [
        'driver' => 'redis',
        'connection' => 'cache',
        'lock_connection' => 'default',
    ],
],

Key things to alert on

  • Hit rate drop — from 90% to 60% suggests TTL or key-generation bug
  • Latency spike — cache p95 > 20ms usually means the Redis box is under pressure
  • Eviction rate — Redis evicted_keys growing means cache is too small
  • Key cardinality explosion — wildcard patterns ballooning (e.g. a cached-per-user value instead of per-plan)

THE EASY WAY

NightOwl tracks cache ops per request

NightOwl's cache watcher logs every hit, miss, and write with duration, tied to the request that triggered it. You see per-route cache hit rate, top missed patterns, and the slowest cache calls across all traffic — no custom event listeners required.

bash
composer require nightowl/agent
php artisan nightowl:install

Frequently asked questions

How do I monitor Laravel cache hit rates?

Hook into CacheMissed and CacheHit events in AppServiceProvider. Count hits vs misses per key pattern (not per key) and aggregate by minute or hour. A healthy app-level cache hits 80-95% of the time; below 50% usually means a cache isn't doing what you think it is.

What's a good cache hit rate for Laravel?

Depends on the use case. Config caches should be ~100%, session caches 95%+, read-through object caches 80-95%, write-heavy caches can be lower. The absolute number matters less than the trend — a drop from 90% to 60% over a week is a real signal even if 60% would be fine for another app.

Should I use Redis or Memcached for Laravel cache?

Redis for most production apps in 2026. It supports more data types, has better persistence options, and is already required for Horizon, queues, and broadcasting. Memcached is slightly faster for pure get/set but that rarely matters. Use the same Redis cluster for cache + sessions + queues if scale allows.

How do I debug a Laravel cache that isn't being hit?

Log cache operations with Event::listen(CacheHit::class, ...) and CacheMissed::class. Check for key-mismatch bugs (different prefix, hashing, serialization), unexpected TTLs, or cache::flush() calls on deploy. If you use tagged caches, verify the driver supports them — only Redis, Memcached, DynamoDB, and array cache do.

Does Laravel cache work across multiple servers?

Only if the cache store is shared. The default file and database stores work per-server (not shared). Redis, Memcached, and DynamoDB are shared by design. If you're running Laravel behind a load balancer with file caching enabled, each server has its own cache — expect weird inconsistencies.

How do I monitor cache latency in Laravel?

Wrap Cache::get and put calls to time them, or use an APM that records cache operations with duration. p95 cache latency should be under 5ms for Redis, under 10ms for Memcached. Latency spikes usually mean network issues between your app and the cache box, or eviction pressure from a cache that's too small.

What's cache stampede and how do I prevent it?

A cache stampede happens when a popular key expires and 100 requests simultaneously try to recompute it, all hitting the database. Fix with Cache::lock() or atomic operations: the first request acquires the lock, recomputes and stores the value, everyone else waits or falls back to a stale value.

PRICING

Flat pricing. No event caps. No per-seat fees.

14-day free trial, no credit card. Your PostgreSQL, your data.

HOBBY

$5 /month

1 app · 14 days lookback · all Laravel events

TEAM

$15 /month

Up to 3 connected apps · unlimited environments · all Laravel events

AGENCY

$69 /month

Unlimited apps · unlimited agent instances · same flat rate at any traffic

Related