← Back to Developer Blog
💻 DeveloperMarch 3, 20268 min read

Redis Caching: Make Your App 10x Faster

Database queries killing your performance? Redis caching can make your app instant. Here's how to do it right.

By Raspib Technology Team

Redis Caching: Make Your App 10x Faster

Your dashboard takes 3 seconds to load. Same data. Every time.

Redis can make it instant.

Here's how.

The Problem

public function dashboard()
{
    $stats = [
        'total_users' => User::count(),
        'total_orders' => Order::count(),
        'revenue' => Order::sum('total'),
        'pending_orders' => Order::where('status', 'pending')->count(),
    ];
    
    return view('dashboard', $stats);
}

4 database queries. Every page load. Even though data changes once per hour.

Basic Caching

public function dashboard()
{
    $stats = Cache::remember('dashboard_stats', 3600, function () {
        return [
            'total_users' => User::count(),
            'total_orders' => Order::count(),
            'revenue' => Order::sum('total'),
            'pending_orders' => Order::where('status', 'pending')->count(),
        ];
    });
    
    return view('dashboard', $stats);
}

First request: Runs queries, caches result.
Next 3600 seconds: Returns cached data instantly.

Performance:

  • Before: 3.2 seconds
  • After: 0.05 seconds

Setup Redis (Laravel)

composer require predis/predis
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
php artisan config:clear

Done.

Cache Strategies

1. Cache Expensive Queries

// Bad: Query every time
$products = Product::with('category', 'images')
    ->where('featured', true)
    ->get();

// Good: Cache for 1 hour
$products = Cache::remember('featured_products', 3600, function () {
    return Product::with('category', 'images')
        ->where('featured', true)
        ->get();
});

2. Cache Per User

$userId = auth()->id();

$orders = Cache::remember("user_{$userId}_orders", 600, function () use ($userId) {
    return Order::where('user_id', $userId)
        ->with('items')
        ->latest()
        ->get();
});

Each user has their own cache.

3. Cache with Tags

// Cache with tags
Cache::tags(['products', 'featured'])->put('featured_products', $products, 3600);

// Invalidate all product caches
Cache::tags('products')->flush();

Use case: When product updates, clear all product-related caches.

Invalidating Cache

Manual Invalidation

public function update(Request $request, Product $product)
{
    $product->update($request->validated());
    
    // Clear cache
    Cache::forget('featured_products');
    Cache::forget("product_{$product->id}");
    
    return response()->json($product);
}

Automatic Invalidation (Model Events)

class Product extends Model
{
    protected static function booted()
    {
        static::saved(function ($product) {
            Cache::forget('featured_products');
            Cache::forget("product_{$product->id}");
        });
        
        static::deleted(function ($product) {
            Cache::forget('featured_products');
            Cache::forget("product_{$product->id}");
        });
    }
}

Cache clears automatically when product changes.

Real Project Example

Client: News website, homepage loading slow

Before caching:

public function index()
{
    $data = [
        'latest_news' => News::latest()->take(10)->get(),
        'trending' => News::orderBy('views', 'desc')->take(5)->get(),
        'categories' => Category::withCount('news')->get(),
    ];
    
    return view('home', $data);
}
  • Load time: 2.8 seconds
  • Database queries: 13
  • Server load: High

After caching:

public function index()
{
    $data = Cache::remember('homepage_data', 300, function () {
        return [
            'latest_news' => News::latest()->take(10)->get(),
            'trending' => News::orderBy('views', 'desc')->take(5)->get(),
            'categories' => Category::withCount('news')->get(),
        ];
    });
    
    return view('home', $data);
}
  • Load time: 0.2 seconds
  • Database queries: 0 (cached)
  • Server load: 70% reduction

Cache Patterns

1. Cache-Aside

// Check cache first
$user = Cache::get("user_{$id}");

if (!$user) {
    // Not in cache, get from database
    $user = User::find($id);
    
    // Store in cache
    Cache::put("user_{$id}", $user, 3600);
}

return $user;

2. Write-Through

public function update(Request $request, User $user)
{
    $user->update($request->validated());
    
    // Update cache immediately
    Cache::put("user_{$user->id}", $user, 3600);
    
    return $user;
}

3. Write-Behind

public function incrementViews(Product $product)
{
    // Increment in cache
    Cache::increment("product_{$product->id}_views");
    
    // Update database later (queue job)
    UpdateProductViews::dispatch($product->id)->delay(now()->addMinutes(5));
}

What to Cache

Always cache:

  • Expensive queries (> 100ms)
  • Data that rarely changes
  • Aggregations (counts, sums)
  • API responses from external services

Never cache:

  • User-specific sensitive data
  • Real-time data
  • Data that changes constantly
  • Small, fast queries

Cache Duration

// Static content: 1 day
Cache::remember('footer_links', 86400, fn() => Link::all());

// Semi-static: 1 hour
Cache::remember('featured_products', 3600, fn() => Product::featured()->get());

// Dynamic: 5 minutes
Cache::remember('trending_posts', 300, fn() => Post::trending()->get());

// Very dynamic: 30 seconds
Cache::remember('active_users', 30, fn() => User::online()->count());

Monitoring Cache

Cache Hit Rate

// Track cache hits
$cacheHits = Cache::get('cache_hits', 0);
$cacheMisses = Cache::get('cache_misses', 0);

$hitRate = $cacheHits / ($cacheHits + $cacheMisses) * 100;

// Aim for > 80% hit rate

Cache Size

# Redis CLI
redis-cli
> INFO memory
> DBSIZE

Monitor memory usage. Clear old keys if needed.

Common Mistakes

Mistake 1: Caching Everything

// Don't cache fast queries
Cache::remember('user_count', 3600, fn() => User::count());
// If User table is small, query is instant. Caching adds overhead.

Mistake 2: No Expiration

// Bad: Cache forever
Cache::forever('data', $value);

// Good: Always set expiration
Cache::put('data', $value, 3600);

Mistake 3: Not Invalidating

// Update product
$product->update(['price' => 2000]);

// Forgot to clear cache
// Users still see old price

Always invalidate related caches.

Node.js Redis Caching

const redis = require('redis');
const client = redis.createClient();

// Cache data
async function getProducts() {
  const cached = await client.get('products');
  
  if (cached) {
    return JSON.parse(cached);
  }
  
  const products = await db.query('SELECT * FROM products');
  
  await client.setEx('products', 3600, JSON.stringify(products));
  
  return products;
}

Bottom Line

Redis caching is the easiest performance win.

Cache expensive queries. Set reasonable expiration. Invalidate when data changes.

Can make your app 10x faster with minimal code.


Need performance optimization?

We optimize slow applications for Nigerian businesses. Database tuning, caching, scaling.

📞 WhatsApp: +234 708 711 0468
📧 info@raspibtech.com
📍 Lagos Island

Related:

Need Help with Your Project?

Let's discuss how Raspib Technology can help transform your business

Related Articles

Redis Caching Guide - Speed Up Laravel Apps