Laravel Caching with Redis: Step-by-Step Guide

·

·

Redis is an in-memory data store that makes Laravel applications faster by caching expensive queries, HTML fragments, and session data. When configured correctly, Redis reduces database load and improves response times under traffic spikes.

Installing and Configuring Redis

Install the Redis server and PHP redis extension on your server or use a managed service like AWS ElastiCache.

Laravel connects through config/database.php redis section and environment variables.

Step 1: Install Redis and the PHP extension

On Ubuntu run sudo apt install redis-server php-redis. Verify with redis-cli ping returning PONG.

For Docker, add a redis service and point REDIS_HOST to the container hostname.

sudo apt install redis-server php-redis
redis-cli ping

Step 2: Set cache and session drivers

In .env set CACHE_STORE=redis and SESSION_DRIVER=redis for unified in-memory storage.

Separate databases using REDIS_CACHE_DB=1 and REDIS_DB=0 to isolate sessions from cache keys.

CACHE_STORE=redis
SESSION_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Step 3: Install Predis or phpredis

Laravel works with the phpredis extension natively. Alternatively composer require predis/predis for pure PHP client.

phpredis is faster at scale. Ensure extension is loaded: php -m | grep redis.

composer require predis/predis

Step 4: Verify connectivity with Tinker

Run Cache::put('ping', 'pong', 60) and Cache::get('ping') in php artisan tinker.

If connection fails, check REDIS_PASSWORD, bind address in redis.conf, and firewall rules on port 6379.

Cache::put('ping', 'pong', 60);
Cache::get('ping');

Cache Facade Patterns

The Cache facade provides get, put, remember, forget, and flush operations with TTL support.

Use descriptive key prefixes like products:list:page:1 so debugging with redis-cli KEYS is manageable.

Step 1: Cache query results with remember()

Wrap expensive queries: Cache::remember('dashboard.stats', 300, fn() => DB::table(…)->get()).

The closure runs only on cache miss. TTL is in seconds. Choose TTL based on acceptable staleness.

$stats = Cache::remember('dashboard.stats', 300, function () {
    return DashboardService::computeStats();
});

Step 2: Invalidate cache on writes

After updating a product, call Cache::forget('product.'.$id) or flush tagged entries.

Pair observers or event listeners with cache invalidation so users never see stale prices or inventory counts.

Cache::forget('product.'.$product->id);

Step 3: Use cache tags for grouped invalidation

Cache::tags(['products'])->put($key, $value, $ttl) groups related keys. Flush all product cache with Cache::tags(['products'])->flush().

Tags require Redis or Memcached. They are unavailable on file or database cache drivers.

Cache::tags(['products'])->put('list', $products, 3600);
Cache::tags(['products'])->flush();

Step 4: Add HTTP cache headers at the edge

Combine application cache with CDN caching for public pages. Set ETag or Cache-Control in middleware.

Application Redis cache and HTTP cache solve different layers. Use both for maximum throughput.

  • Redis for computed data
  • CDN for static assets

Production Redis Best Practices

Production Redis needs persistence policies, memory limits, and monitoring to stay reliable.

Horizon and Laravel Telescope help observe queue and cache behavior in real time.

Step 1: Configure maxmemory and eviction

Set maxmemory in redis.conf and choose an eviction policy like allkeys-lru when memory is full.

Monitor used_memory with redis-cli INFO memory. Scale vertically or add replicas before evictions hurt hit rate.

maxmemory 256mb
maxmemory-policy allkeys-lru

Step 2: Use Redis for queues with Horizon

Set QUEUE_CONNECTION=redis and install laravel/horizon for dashboard and worker management.

Run php artisan horizon in production supervised by systemd. Horizon balances workers across queues.

composer require laravel/horizon
php artisan horizon:install

Step 3: Serialize carefully

Eloquent collections cache well but watch for large payloads. Cache IDs and re-query with eager loading when objects are huge.

Use Cache::rememberForever() only for truly static reference data like country lists.

Cache::rememberForever('countries', fn () => Country::orderBy('name')->get());

Step 4: Benchmark before and after

Use Laravel Debugbar or clockwork to compare query counts with cache on and off.

Document cache keys and TTLs in your runbook so on-call engineers can flush the right keys during incidents.

php artisan cache:clear

Aadyanex builds production-ready Laravel applications with clean architecture, secure APIs, and long-term support.