Slow pages drive users away and hurt SEO rankings. Often the culprit is a heavy database query or a computation repeated on every request. Caching solves this by storing a result once, then serving it instantly over and over. This tutorial covers caching in Laravel 10/11 practically, complete with real code and an invalidation strategy.
How Cache Works in Laravel
Laravel provides a uniform cache API through the Cache facade. Whatever the driver — file, database, Redis, Memcached — your code stays the same. The core concept is simple: store a value under a key, retrieve it by that key, and let it expire after a set duration.
use Illuminate\Support\Facades\Cache;
Cache::put('key', 'value', now()->addHour());
$value = Cache::get('key');
1. Choosing a Cache Driver
The driver is set in .env. The default is file, which is enough for small apps since it needs no extra service:
CACHE_STORE=file
For maximum performance and features like cache tags, use redis:
CACHE_STORE=redis
Redis keeps the cache in memory so access is very fast, and it supports advanced features unavailable in the file driver.
Remember that the driver determines where cached data lives, not how you call it. That's why you can start with the file driver during development, then switch to redis in production without changing a single line of application code. This is the strength of Laravel's cache abstraction: your code stays consistent while the infrastructure is free to change with your scale.
2. The remember() Pattern for Expensive Queries
The most useful pattern is remember(): if the data is in the cache, return it; if not, run the closure, store the result, then return it. Perfect for wrapping heavy queries that are called often on a homepage or dashboard:
$products = Cache::remember('featured_products', 3600, function () {
return Product::where('is_featured', true)
->with('category')
->orderBy('sold', 'desc')
->take(10)
->get();
});
The query touches the database only once per hour (3600 seconds). Subsequent requests fetch from cache in milliseconds. For rarely-changing data, use rememberForever() which stores without expiration:
$settings = Cache::rememberForever('site_settings', function () {
return Setting::pluck('value', 'key');
});
3. Storing and Retrieving Manually
Besides remember(), you can manage the cache manually:
Cache::put('visitor_count', 100, 600); // 10 minutes
Cache::increment('visitor_count');
Cache::has('visitor_count'); // true
Cache::forget('visitor_count'); // remove
Cache::flush(); // remove everything (careful!)
4. Cache Tags for Grouping
When you have many cached entries, deleting them one by one is tedious. Cache tags (only on redis/memcached drivers) group entries so they can be cleared together:
Cache::tags(['products', 'homepage'])->put('best_sellers', $data, 3600);
// Clear all caches tagged 'products' in one go
Cache::tags(['products'])->flush();
This is very handy: when a product is updated, you just clear the products tag without touching other caches like sessions or settings.
5. Cache Invalidation Strategy
There's a famous saying: "the two hardest things in computer science are naming variables and cache invalidation." The core problem: stale cache serves old data. A reliable strategy is to clear the cache whenever the source data changes. Use model events to automate it:
class Product extends Model
{
protected static function booted(): void
{
static::saved(fn () => Cache::forget('featured_products'));
static::deleted(fn () => Cache::forget('featured_products'));
}
}
This way, whenever a product is saved or deleted, the related cache is automatically cleared so the next request rebuilds fresh data. For large groups, combine this with cache tags as in the previous step.
6. Framework Caches: Config, Route, and View
Beyond application cache, Laravel has caches to speed up the framework itself. These are required in production, but avoid them locally while changing configuration:
php artisan config:cache # merge all config into one file
php artisan route:cache # compile routes for speed
php artisan view:cache # pre-compile Blade templates
After deploying changes, clear them so you don't serve the old version:
php artisan optimize:clear
The optimize:clear command clears config, route, view, and application cache all at once.
7. Common Mistakes to Avoid
- Caching frequently-changing data: data like real-time stock should not be cached for long, or must be invalidated when it changes.
- Forgetting to clear config cache locally: editing
.envhas no effect if config is already cached. Runphp artisan config:clear. - Non-unique cache keys: make sure the key includes relevant parameters, e.g.
"user_{$id}_orders", so data doesn't leak between users.
By applying remember() to expensive queries, cache tags for grouping, invalidation via model events, and framework caches in production, you can slash database load dramatically and make your app feel far more responsive.