spatie/laravel-responsecache
Cache full Laravel responses to speed up your app. Automatically caches successful text-based GET requests (HTML/JSON), with easy middleware per route, configurable lifetimes, and optional stale-while-revalidate “grace” caching to refresh in the background.
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require spatie/laravel-responsecache
Publish the config file (optional):
php artisan vendor:publish --provider="Spatie\ResponseCache\ResponseCacheServiceProvider" --tag="responsecache-config"
First Use Case: Apply the middleware to a route group or individual route:
use Spatie\ResponseCache\Middlewares\CacheResponse;
Route::middleware(CacheResponse::for(minutes(10)))->group(function () {
Route::get('/posts', [PostController::class, 'index']);
});
GET requests returning text-based content (HTML/JSON) for 10 minutes.Where to Look First:
config/responsecache.php for default settings (e.g., cache driver, excluded routes, debug headers).app/Http/Middleware/ to inspect middleware behavior or extend it.Route-Level Caching:
Route::middleware(CacheResponse::for(hours(1)))->get('/dashboard', [DashboardController::class, 'index']);
Route::middleware(FlexibleCacheResponse::for(lifetime: hours(1), grace: minutes(5)))->get('/analytics');
Controller-Level Attributes (Laravel 8+):
use Spatie\ResponseCache\Attributes\Cache;
#[Cache(lifetime: '1 hour')]
public function index() { ... }
Cache Invalidation:
use Spatie\ResponseCache\Facades\ResponseCache;
ResponseCache::clear(); // Clear all
ResponseCache::forget('https://example.com/posts/1'); // Clear specific URL
tags config):
#[Cache(lifetime: '1 hour', tags: ['posts'])]
public function index() { ... }
ResponseCache::clearTags(['posts']); // Invalidate all tagged responses
Conditional Caching:
config/responsecache.php:
'excluded_paths' => [
'admin/*',
'api/*',
],
#[NoCache] attribute to opt-out specific methods:
use Spatie\ResponseCache\Attributes\NoCache;
#[NoCache]
public function sensitiveData() { ... }
Debugging & Monitoring:
'debug_headers' => env('APP_ENV') !== 'production',
X-Response-Cache (HIT, MISS, STALE).Integration with Other Packages:
CacheMissedEvent listeners).CacheResponse middleware.Cache Key Collisions:
CacheResponse::using() to customize the hasher (e.g., xxh128 for speed):
Route::middleware(CacheResponse::using('xxh128')->for(minutes(10)))->get('/search');
State Sharing in Middleware:
handle() and terminate().$request->attributes->add(['cache_state' => $state]);
Post-Response Modifications:
AppServiceProvider@finishRequest).terminate() (default in v8.3.0+):
'defer_cache_storage' => true, // config/responsecache.php
Race Conditions:
null cache values may cause race conditions between has() and get().null as a cache miss (fixed in v8.4.0).CSRF Tokens in Cached Responses:
CsrfTokenReplacer (enabled by default) to dynamically replace tokens:
'csrf_token_replacer' => true, // config/responsecache.php
Flexible Cache Grace Periods:
X-Response-Cache-Stale headers and adjust grace periods:
FlexibleCacheResponse::for(lifetime: hours(1), grace: minutes(10));
Tag-Based Invalidation:
ResponseCache::clearTags(['posts', 'users']);
Inspect Headers:
X-Response-Cache, X-Response-Cache-Tags, and X-Response-Cache-Stale in browser dev tools.Log Cache Events:
use Spatie\ResponseCache\Events\CacheMissed;
CacheMissed::subscribe(function (CacheMissed $event) {
Log::info('Cache missed for:', $event->url);
});
Disable Caching Temporarily:
app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ... other middleware
// \Spatie\ResponseCache\Middlewares\CacheResponse::class, // Comment out
],
];
Clear Cache Strategically:
ResponseCache::forget() with URL patterns:
ResponseCache::forget('https://example.com/posts/*'); // Clear all posts
Custom Cache Drivers:
Spatie\ResponseCache\CacheProfiles\CacheProfile for custom storage (e.g., Redis, DynamoDB).Middleware Decorators:
CacheResponse or FlexibleCacheResponse to add logic:
use Spatie\ResponseCache\Middlewares\CacheResponse;
class CustomCacheResponse extends CacheResponse {
public function handle($request, Closure $next) {
// Pre-process request
$response = parent::handle($request, $next);
// Post-process response
return $response;
}
}
Attribute Interceptors:
ResponseCache::extend('custom', function () {
return CacheResponse::using('xxh128')->for(minutes(30));
});
Event Listeners:
CacheMissed::subscribe(function ($event) {
// Send alert or log
});
Cache Key Customization:
CacheResponse::using()->for(minutes(10))->withKey(function ($request) {
return md5($request->fullUrl() . $request->user()?->id);
});
Cache Driver:
file. For production, use redis or database:
'cache_driver' => env('CACHE_DRIVER', 'redis'),
Excluded Paths:
'excluded_paths' => [
'healthcheck',
'api/*',
'admin/*',
'webhooks/*',
],
Debug Headers:
'debug_headers' => app()->environment('local'),
Cache Lifetime:
CacheResponse::for(seconds(3600)) // 1 hour (integer)
How can I help you explore Laravel packages today?