Files
SealShare/.claude/skills/laravel-best-practices/rules/caching.md
T
Andreas Reinhold / reiniandClaude Opus 5 92b3b3de56 Regenerate Boost guidelines and skills
Generated by boost:update for Boost 2.8, which replaces the pest-testing
skill with testing-best-practices and adds infer-conventions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYnWFt9pJEwvAmNFN38XD
2026-09-10 10:42:22 +02:00

3.3 KiB

Caching Best Practices

Use Cache::remember() for Cache-Aside Reads

Cache::remember() implements a cache-aside read without a separate truthiness check. It does not prevent concurrent requests from computing the same missing value; use an atomic lock when duplicate computation must be prevented.

The manual version below incorrectly treats valid falsy values, such as false or 0, as cache misses.

Incorrect:

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

Correct:

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

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

For frequently read keys, Cache::flexible() can serve stale data during a defined stale period and register a deferred refresh. During an HTTP request, that refresh normally runs after the response; it is not a durable background job. Once the stale period has elapsed, the request recomputes the value synchronously.

Synchronous expiration:

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

Stale-while-revalidate tradeoff:

Cache::flexible('users', [300, 600], fn () => User::all());

This value is fresh for five minutes and may be served stale until ten minutes after it was cached.

Use Cache::memo() to Avoid Redundant Hits Within an Execution

If the same cache key is read repeatedly during one request or job, memo() decorates a cache store and retains resolved values in memory for that execution.

$settings = Cache::memo()->get('settings');

Repeated reads through the same memoized store avoid additional store lookups. Writes through the memoized store update or invalidate its in-memory values as appropriate.

Tags group related entries for invalidation without tracking each key. Cache tags are not supported by the file, dynamodb, or database drivers; confirm support before choosing a store.

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

Use Cache::add() for Atomic Conditional Writes

add() atomically writes a value only when the key does not already exist.

Incorrect:

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

Correct:

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

Use Cache::lock() rather than an ordinary cache key when lock ownership and safe release are required.

Use once() for In-Process Memoization

once() memoizes a callback's return value for the current request or job. Calls made from an object instance are scoped to that instance. Unlike Cache::memo(), once() does not read from an external cache store.

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

Repeated calls return the memoized result without rerunning the callback. Use once() for repeated computation within one execution. Use Cache::memo() to memoize access to an underlying store that can also persist values across executions.

Configure Failover Cache Stores in Production

The failover driver tries each configured store in order when a store operation throws an exception. It does not consult later stores for an ordinary cache miss, and data is not replicated between stores.

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