resources/boost/skills/responsecache-development/SKILL.md
Cache entire HTTP responses using spatie/laravel-responsecache, including standard caching, flexible (stale-while-revalidate) caching, cache profiles, replacers, and selective cache clearing.
npx skillsauth add spatie/laravel-responsecache responsecache-developmentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when working with HTTP response caching in a Laravel application using spatie/laravel-responsecache. This includes adding cache middleware to routes, configuring cache profiles, clearing cached responses, creating custom replacers, or working with flexible (stale-while-revalidate) caching.
Use the CacheResponse middleware to cache entire responses:
use Spatie\ResponseCache\Middlewares\CacheResponse;
// Cache with default lifetime (from config)
Route::middleware(CacheResponse::class)->group(function () {
Route::get('/posts', [PostController::class, 'index']);
});
// Cache with custom lifetime using CarbonInterval
Route::middleware(CacheResponse::for(lifetime: CarbonInterval::minutes(10)))->group(function () {
Route::get('/posts', [PostController::class, 'index']);
});
// Cache with tags for selective clearing
Route::middleware(CacheResponse::for(lifetime: CarbonInterval::hour(), tags: 'posts'))->group(function () {
Route::get('/posts', [PostController::class, 'index']);
});
Serve stale content while refreshing in the background using FlexibleCacheResponse:
use Spatie\ResponseCache\Middlewares\FlexibleCacheResponse;
Route::middleware(FlexibleCacheResponse::for(
lifetime: CarbonInterval::minutes(5),
grace: CarbonInterval::minute(),
tags: 'posts',
))->group(function () {
Route::get('/posts', [PostController::class, 'index']);
});
The response is considered fresh for lifetime seconds. After that, stale content is served while a background refresh happens within the grace period.
Use attributes instead of middleware for per-action control:
use Spatie\ResponseCache\Attributes\Cache;
use Spatie\ResponseCache\Attributes\FlexibleCache;
use Spatie\ResponseCache\Attributes\NoCache;
class PostController
{
// Cache with custom lifetime (seconds) and tags
#[Cache(lifetime: 600, tags: ['posts'])]
public function index() { /* ... */ }
// Flexible cache with lifetime and grace (seconds)
#[FlexibleCache(lifetime: 300, grace: 60, tags: ['posts'])]
public function popular() { /* ... */ }
// Prevent caching on a specific action
#[NoCache]
public function create() { /* ... */ }
}
Attributes work when the CacheResponse or FlexibleCacheResponse middleware is applied to the route.
Use the DoNotCacheResponse middleware to prevent caching:
use Spatie\ResponseCache\Middlewares\DoNotCacheResponse;
Route::middleware(DoNotCacheResponse::class)->group(function () {
Route::get('/account', [AccountController::class, 'show']);
});
Or use the #[NoCache] attribute on individual controller methods.
use Spatie\ResponseCache\Facades\ResponseCache;
// Clear all cached responses
ResponseCache::clear();
// Clear only responses with specific tags (requires a tag-supporting cache driver)
ResponseCache::clear(['posts']);
// Forget specific URLs
ResponseCache::forget('/posts');
ResponseCache::forget(['/posts', '/posts/popular']);
// Forget specific URLs with tags
ResponseCache::forget('/posts', ['posts']);
// Selective clearing with the fluent API
ResponseCache::selectCachedItems()
->forUrls('/posts', '/posts/popular')
->usingTags('posts')
->forget();
Clear via Artisan:
php artisan responsecache:clear
Implement the CacheProfile interface to control what gets cached:
use Illuminate\Http\Request;
use Spatie\ResponseCache\CacheProfiles\CacheProfile;
use Symfony\Component\HttpFoundation\Response;
class CustomCacheProfile implements CacheProfile
{
public function enabled(Request $request): bool
{
// Return false to disable caching entirely
return true;
}
public function shouldCacheRequest(Request $request): bool
{
return $request->isMethod('GET');
}
public function shouldCacheResponse(Response $response): bool
{
return $response->isSuccessful();
}
public function cacheLifetimeInSeconds(Request $request): int
{
return 3600;
}
public function useCacheNameSuffix(Request $request): string
{
// Return a unique suffix to separate caches, e.g. per user
return auth()->check() ? (string) auth()->id() : '';
}
}
Register in config/responsecache.php:
'cache_profile' => App\CacheProfiles\CustomCacheProfile::class,
You can also extend Spatie\ResponseCache\CacheProfiles\BaseCacheProfile for sensible defaults.
Replacers swap dynamic content (like CSRF tokens) so cached responses stay valid:
use Spatie\ResponseCache\Replacers\Replacer;
use Symfony\Component\HttpFoundation\Response;
class UserNameReplacer implements Replacer
{
public function prepareResponseToCache(Response $response): void
{
// Replace the actual value with a placeholder before caching
$content = $response->getContent();
$response->setContent(str_replace(
auth()->user()->name,
'<USERNAME_PLACEHOLDER>',
$content,
));
}
public function replaceInCachedResponse(Response $response): void
{
// Replace the placeholder with the current value when serving
$content = $response->getContent();
$response->setContent(str_replace(
'<USERNAME_PLACEHOLDER>',
auth()->user()?->name ?? '',
$content,
));
}
}
Register in config/responsecache.php:
'replacers' => [
\Spatie\ResponseCache\Replacers\CsrfTokenReplacer::class,
\App\Replacers\UserNameReplacer::class,
],
Implement RequestHasher to customize how cache keys are generated:
use Illuminate\Http\Request;
use Spatie\ResponseCache\Hasher\RequestHasher;
class CustomHasher implements RequestHasher
{
public function getHashFor(Request $request): string
{
return hash('xxh128', $request->getUri());
}
}
Register in config/responsecache.php:
'hasher' => App\Hashers\CustomHasher::class,
The package dispatches these events:
ResponseCacheHitEvent — a cached response was served. Properties: $request, $ageInSeconds, $tags.CacheMissedEvent — no cached response found. Properties: $request.ClearingResponseCacheEvent — cache is about to be cleared.ClearedResponseCacheEvent — cache was cleared successfully.ClearingResponseCacheFailedEvent — cache clearing failed.Key configuration options in config/responsecache.php:
enabled — toggle caching on/off (env: RESPONSE_CACHE_ENABLED)cache.store — cache driver to use (env: RESPONSE_CACHE_DRIVER, default: file)cache.lifetime_in_seconds — default cache lifetime (env: RESPONSE_CACHE_LIFETIME, default: 7 days)cache.tag — default tag for cache entriesbypass.header_name / bypass.header_value — header to bypass cache for testingdebug.enabled — add X-Cache-Status, X-Cache-Time, X-Cache-Age, X-Cache-Key headersignored_query_parameters — query params excluded from cache key (UTM tags, gclid, fbclid)cache_profile — class determining what to cachehasher — class generating cache keysserializer — class serializing/unserializing responsesreplacers — classes replacing dynamic content in cached responsesdevelopment
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.