Files
laravel-shopping-cart/.claude/skills/laravel-best-practices/rules/caching.md
T
2026-04-09 16:06:44 -06:00

2.3 KiB

Caching Best Practices

Use Cache::remember() Instead of Manual Get/Put

Atomic pattern prevents race conditions and removes boilerplate.

Incorrect:

$val = Cache::get('stats');
if (! $val) {
    $val = $this->computeStats();
    Cache::put('stats', $val, 60);
}

Correct:

$val = Cache::remember('stats', 60, fn () => $this->computeStats());

Use Cache::flexible() for Stale-While-Revalidate

On high-traffic keys, one user always gets a slow response when the cache expires. flexible() serves slightly stale data while refreshing in the background.

Incorrect: Cache::remember('users', 300, fn () => User::all());

Correct: Cache::flexible('users', [300, 600], fn () => User::all()); — fresh for 5 min, stale-but-served up to 10 min, refreshes via deferred function.

Use Cache::memo() to Avoid Redundant Hits Within a Request

If the same cache key is read multiple times per request (e.g., a service called from multiple places), memo() stores the resolved value in memory.

Cache::memo()->get('settings'); — 5 calls = 1 Redis round-trip instead of 5.

Without tags, invalidating a group of entries requires tracking every key. Tags let you flush atomically. Only works with redis, memcached, dynamodb — not file or database.

Cache::tags(['user-1'])->flush();

Use Cache::add() for Atomic Conditional Writes

add() only writes if the key does not exist — atomic, no race condition between checking and writing.

Incorrect: if (! Cache::has('lock')) { Cache::put('lock', true, 10); }

Correct: Cache::add('lock', true, 10);

Use once() for Per-Request Memoization

once() memoizes a function's return value for the lifetime of the object (or request for closures). Unlike Cache::memo(), it doesn't hit the cache store at all — pure in-memory.

public function roles(): Collection
{
    return once(fn () => $this->loadRoles());
}

Multiple calls return the cached result without re-executing. Use once() for expensive computations called multiple times per request. Use Cache::memo() when you also want cross-request caching.

Configure Failover Cache Stores in Production

If Redis goes down, the app falls back to a secondary store automatically.

'failover' => ['driver' => 'failover', 'stores' => ['redis', 'database']],