
August 17, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Slow database queries and repeated computation are the bottlenecks I see most often when auditing PHP applications. Redis caching: Speed Up Your Laravel/PHP App is not a package install—it is an architecture choice about volatility, serialization cost, and invalidation rules. Whether you run a high-traffic store or a legal-tech portal, moving from file-based caching to Redis 8.10 is often the highest-ROI infrastructure change you can make. For broader performance work, see our speed optimization services in Nepal.
CACHE_STORE=redis, isolate cache/sessions/queues on separate Redis DB indices, cache only shared read-heavy data with tagged keys and TTLs, and use atomic locks to stop thundering-herd database spikes.Before you change drivers, decide what freshness your users require. Real-time booking flows need tighter invalidation than a category listing page. If you are building APIs, pair this guide with Laravel API best practices so cached responses stay consistent with your contract. A Laravel developer in Nepal working on multi-server setups should also plan session and queue separation from day one.
How do you configure Redis as the primary cache driver in Laravel 13?
Laravel 13.x ships with first-class Redis support, but production needs tuned connections, serialization, and prefixing. PHP 8.3 is the minimum for Laravel 13; PHP 8.5 is the current anchor version and what I target on new Ubuntu 24 servers.
Choosing between PhpRedis and Predis
PhpRedis is a C extension with lower overhead under load. Predis installs via Composer only and is fine for local dev. On every production server I manage, I install PhpRedis through the OS package or PECL.
# Install PhpRedis on Ubuntu 24.04 (PHP 8.5)
sudo apt-get install php8.5-redis
# Verify
php -m | grep redis
# Fallback via PECL
sudo pecl install redis
echo "extension=redis.so" | sudo tee /etc/php/8.5/mods-available/redis.ini
sudo phpenmod redis Set your environment and confirm Laravel sees Redis:
# .env
CACHE_STORE=redis
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_CACHE_DB=1
SESSION_DRIVER=redis
SESSION_CONNECTION=session
QUEUE_CONNECTION=redis Separating cache, sessions, and queues
A common mistake is putting cache, sessions, queues, and Pub/Sub on Redis database 0. Running php artisan cache:clear can then wipe sessions or queued jobs. Assign distinct database indices in config/database.php.
// config/database.php
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
'persistent' => env('REDIS_PERSISTENT', true),
],
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
'session' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_SESSION_DB', '2'),
],
], The official Laravel cache documentation covers driver configuration. For Redis server options, see the Redis documentation.
What are the most effective caching patterns for Eloquent queries?
Caching full Eloquent models is often wasteful. Serialized models carry hidden fields, casts, and relationship metadata that bloat memory. Cache the shape your view or API actually needs. This cuts payload size and makes invalidation predictable.
Repository layer with tagged caching
Tags enable group invalidation. Without them, clearing all posts in category X means guessing every key. Redis supports tags natively; Memcached does not. Keep Cache::remember() out of controllers—wrap queries in a repository or service. For a deeper pattern write-up, see Laravel repository pattern explained with real code.
class ProductRepository
{
public function getActiveProducts(int $categoryId): Collection
{
$cacheKey = "products:category:{$categoryId}:active";
return Cache::tags(['products', "category:{$categoryId}"])
->remember($cacheKey, now()->addHours(6), function () use ($categoryId) {
return Product::where('category_id', $categoryId)
->where('is_active', true)
->select(['id', 'name', 'price', 'slug', 'thumbnail'])
->orderByDesc('updated_at')
->limit(50)
->get();
});
}
public function invalidateCategory(int $categoryId): void
{
Cache::tags(["category:{$categoryId}"])->flush();
}
} Compare tag behaviour in Laravel cache tags with Redis vs Memcached. On catalog-heavy stores like Nepal Gift Card, tagged category caches pay off quickly.
Stopping the thundering herd with atomic locks
When a hot key expires, many requests may hit MySQL at once. That thundering herd can stall your database. Use atomic locks so one worker regenerates while others wait or serve stale data.
$key = "products:category:{$categoryId}:active";
return Cache::lock("lock:{$key}", 30)->block(5, function () use ($key, $categoryId) {
return Cache::remember($key, now()->addHours(6), function () use ($categoryId) {
return Product::where('category_id', $categoryId)
->where('is_active', true)
->get();
});
}); Pair this with query tuning from MySQL query optimization for high-traffic apps. Even perfect caching cannot fix an N+1 query inside the regeneration callback.
How does Redis compare to file and database caching for PHP applications?
File caching works for low-traffic brochure sites. Database caching adds query latency on every miss. Redis wins when read volume is high, data changes slowly relative to reads, or you need sub-millisecond session and API response times.
| Criteria | File Cache | Database Cache | Redis Cache |
|---|---|---|---|
| Read latency | 5–50 ms (disk I/O) | 10–100 ms (query + network) | <1 ms (in-memory) |
| Concurrency | Poor (file locks) | Moderate (row locks) | Excellent (non-blocking) |
| Tag support | No | Yes (slow) | Yes (native sets) |
| Atomic ops | No | Limited | Full (INCR, SETNX, Lua) |
| Multi-server sessions | Unsafe | Slow under load | Ideal |
| Infra cost (Nepal VPS) | Zero | Uses existing DB | Rs 1,500–5,000/mo (~USD 11–37) |
| Best for | Dev, static config | Low-traffic apps | Production, APIs, eCommerce |
For budget-sensitive Nepal projects, I often start on file cache and migrate when monitoring shows miss storms. The jump to Redis typically yields 10–50× throughput on read-heavy endpoints. Operational overhead—monitoring, backups, firewall rules—must be justified by traffic. Read improving web performance with caching strategies for the full picture.
What are the common cache invalidation mistakes in production Laravel apps?
Invalidation bugs erode trust faster than slow pages. Stale inventory, wrong prices, or outdated legal content are hard to debug because the app code looks correct. These mistakes recur on projects I audit, from legal portals to eCommerce platforms.
Missing model observer hooks
If you cache product listings but skip invalidation on update, users see phantom stock. Bind cache clearing to model lifecycle events—not manual controller calls that someone will forget.
class ProductObserver
{
public function saved(Product $product): void
{
Cache::tags(['products', "category:{$product->category_id}"])->flush();
Cache::tags(['products', "product:{$product->id}"])->flush();
}
public function deleted(Product $product): void
{
$this->saved($product);
}
} Over-caching mutable or user-specific data
Carts, dashboards, and admin panels change every request. Caching them creates ghost state. Reserve Redis for shared reference data: navigation menus, category trees, pricing tiers, feature flags, and aggregated stats. Use database query caching strategies only where the data is truly shared.
Ignoring serialization changes after deploy
Adding a model attribute or changing a cast can break cached serialized objects. After schema-affecting deploys, version your keys or run a targeted flush on the isolated cache DB.
$version = config('app.cache_version', 'v1');
$key = "{$version}:products:category:{$categoryId}";
// deploy.sh — safe because cache uses REDIS_CACHE_DB=1
php artisan config:cache
php artisan cache:clear How do you harden and monitor Redis on a production Ubuntu server?
Redis is fast because it holds data in RAM. That same trait makes misconfiguration costly. Bind to localhost or a private network, require a strong password, and cap memory so one cache spike cannot take down the whole VPS.
Baseline redis.conf settings
- Set
requirepassand store the password only in.env. - Set
maxmemoryto 70–80% of available RAM after PHP-FPM and MySQL. - Use
maxmemory-policy allkeys-lrufor pure cache workloads. - Disable dangerous commands:
rename-command FLUSHALL "". - Enable AOF or RDB only if you store non-regenerable data in Redis.
# /etc/redis/redis.conf (excerpt)
bind 127.0.0.1 ::1
requirepass your-strong-password
maxmemory 512mb
maxmemory-policy allkeys-lru
rename-command FLUSHALL ""
rename-command FLUSHDB "" For server setup beyond Redis, see Linux system administration in Nepal and PHP-FPM tuning for high-traffic websites. Queue workers should run under Laravel Horizon when Redis backs your job pipeline.
What to watch in production
Track memory usage, evicted keys, connected clients, and hit rate. A climbing evicted_keys counter means your TTLs or maxmemory are wrong—not that you need a bigger server yet.
redis-cli -a "$REDIS_PASSWORD" INFO memory
redis-cli -a "$REDIS_PASSWORD" INFO stats | grep keyspace
redis-cli -a "$REDIS_PASSWORD" --bigkeys On booking systems like Adventure Third Pole Trek, I log cache regeneration time alongside queue latency. A slow regeneration callback shows up before users complain. Validate JSON API payloads with our JSON formatter tool when debugging cached API responses.
PhpRedis connection details and serialization options are documented in the PhpRedis GitHub repository. For broader Redis topology—sentinel, clustering—read Redis persistence and clustering and Redis caching patterns for web apps.
Key Takeaways
- Install PhpRedis, set
CACHE_STORE=redis, and isolate cache, sessions, and queues on separate Redis DB indices. - Cache slim data shapes in repositories—not full Eloquent models—and use tags for group invalidation.
- Apply atomic locks on hot keys so expired cache entries do not trigger a thundering herd on MySQL.
- Invalidate through model observers; never cache carts, dashboards, or other per-user mutable state.
- Version cache keys after deploys that change serialization, and monitor Redis memory plus evicted keys.
- Redis costs Rs 1,500–5,000/month on a Nepal VPS—justify it with measured read latency, not assumptions.
People Also Ask
Is Redis worth it for a small Laravel site in Nepal?
For brochure sites under a few hundred daily visits, file cache is often enough. Redis pays off when you serve APIs, run multiple PHP-FPM workers, need shared sessions across servers, or MySQL slow-query logs show repeated identical reads. Measure first, then upgrade.
Should I use Redis for Laravel sessions and queues too?
Yes on production multi-worker setups. Redis sessions survive horizontal scaling and deploys better than file sessions. Queues on the same Redis instance are fine—just use a separate database index so cache:clear never drops pending jobs.
What TTL should I set for cached Eloquent queries?
Match TTL to business tolerance for staleness. Category menus might live six to twenty-four hours. Product listings often need fifteen minutes to one hour with observer-based invalidation on write. Never use infinite TTL without an explicit invalidation path.
Does Redis caching help Core Web Vitals and SEO?
Faster server response time reduces TTFB, which feeds into LCP on dynamic pages. Redis alone will not fix unoptimized images or bloated JavaScript. Pair caching with guidance from Core Web Vitals optimization and how website speed impacts SEO in Nepal.
Ship faster pages with Redis caching done right
Redis caching to speed up your Laravel/PHP app is one of the most reliable wins I deploy on production systems—but only with clear invalidation rules, isolated databases, and locks on hot keys. Start with your slowest shared read endpoints, measure hit rate for a week, then expand. Need help auditing cache architecture on an existing app? Contact us or explore testing and optimization services to turn latency data into a concrete rollout plan.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

