CLOUD
Guides

Caching Strategies for Web Apps: Developer Guide

CLOUD|February 21, 2026|Updated September 6, 2026|4 min read|502 views
Caching Strategies for Web Apps: Developer Guide

Browser cache, CDN cache, application cache, database cache — 4 caching layers. We explain each and when to use it.

Why Is Caching Essential?

Every successful web application eventually hits the same challenge: traffic increases, but the database and server cannot keep up. The solution is not always upgrading specifications — it is usually implementing a well-designed caching strategy.

Good caching reduces resource consumption by 70-90% and improves response time from hundreds of milliseconds to under 10ms.

The Seven Levels of Caching

Level 1: Browser Cache

The browser stores files locally on the user's device.

# nginx: set browser cache duration
location ~* \.(css|js)$ {
 expires 1y;
 add_header Cache-Control "public, immutable";
}

location ~* \.(jpg|png|gif|webp)$ {
 expires 6M;
 add_header Cache-Control "public";
}

location = /index.html {
 expires -1;
 add_header Cache-Control "no-cache, no-store";
}

Level 2: CDN Cache

# Cloudflare reuses nginx Cache-Control headers above
# Or define them in Cloudflare Transform Rules

Level 3: Application Cache (Redis)

// Laravel: Full page cache
Route::get('/pricing', function {
 return Cache::remember('page:pricing', 3600, function {
 return Inertia::render('Pricing', [
 'plans' => Plan::with('features')->get,
 ]);
 });
});

// Or use HTTP Cache Headers
return response
 ->view('pricing')
 ->header('Cache-Control', 'public, max-age=3600');

Level 4: Query Cache

// Cache results of heavy queries
$stats = Cache::remember('dashboard:stats', 300, function {
 return [
 'total_users' => User::count,
 'active_servers' => Server::where('status', 'active')->count,
 'monthly_revenue' => Invoice::thisMonth->sum('amount'),
 ];
});

// Cache with Tags for selective clearing
Cache::tags(['products'])->remember("product:{$id}", 86400, function use ($id) {
 return Product::with(['category', 'specs', 'pricing'])->find($id);
});

Level 5: Object Cache

// Pre-cache PHP objects
class UserRepository
{
 public function find(int $id): User
 {
 return Cache::remember(
 "user:{$id}",
 1800,
 fn => User::with('permissions', 'subscription')->findOrFail($id)
 );
 }

 public function clearCache(int $id): void
 {
 Cache::forget("user:{$id}");
 }
}

Level 6: Full-Page Cache

// Middleware for full-page caching
class CacheResponse
{
 public function handle(Request $request, Closure $next): Response
 {
 // Do not cache POST requests or authenticated pages
 if ($request->method !== 'GET' || $request->user) {
 return $next($request);
 }

 $cacheKey = 'page:' . md5($request->url);

 if (Cache::has($cacheKey)) {
 return response(Cache::get($cacheKey));
 }

 $response = $next($request);
 Cache::put($cacheKey, $response->getContent, 3600);

 return $response;
 }
}

Level 7: Computed/Memoization Cache

// Memoize results of heavy computations within a single request
class PricingCalculator
{
 private array $memo = [];

 public function calculate(array $config): float
 {
 $key = md5(serialize($config));

 if (!isset($this->memo[$key])) {
 $this->memo[$key] = $this->doHeavyCalculation($config);
 }

 return $this->memo[$key];
 }
}

Cache Invalidation Strategies

1. TTL (Time-To-Live) — Simplest

// Data expires automatically after the duration
Cache::put('data', $value, 3600); // 1 hour
Cache::put('data', $value, now->addDays(7)); // 1 week

Pros: Simple, requires no extra code Cons: Stale data until TTL expires

// Store
Cache::tags(['posts', "user:{$userId}"])->put(
 "posts:user:{$userId}",
 $posts,
 3600
);

// Clear all cache for a specific user
Cache::tags(["user:{$userId}"])->flush;

// Clear all posts
Cache::tags(['posts'])->flush;

3. Event-Driven Invalidation — Most Precise

// When a product is updated, automatically clear cache
class Product extends Model
{
 protected static function booted: void
 {
 static::saved(function (Product $product) {
 Cache::forget("product:{$product->id}");
 Cache::tags(['products'])->flush;
 });
 }
}

Cache Duration Selection Guide

Data Type Appropriate Cache Duration
Application settings 24 hours or more
Product listings 1-6 hours
User data 15-30 minutes
Search results 5-10 minutes
Dashboard statistics 5 minutes
Session data Session lifetime
External API data 1 minute - 1 hour

Caching on cloud.net.sa Servers

cloud.net.sa servers use high-speed NVMe SSDs, allowing Redis to operate at maximum efficiency. With the ability to add RAM at 600 SAR per 2GB, you can scale your cache easily as your application grows.

Recommendation: Dedicate at least 20% of RAM to Redis cache. For an 8GB RAM server, this means allocating 1.5-2GB to Redis.

# Adjust Redis maxmemory
redis-cli config set maxmemory 1500mb
redis-cli config set maxmemory-policy allkeys-lru

Common Caching Mistakes

Cache Stampede

// Problem: 1000 requests simultaneously when cache expires
// Solution: Cache Lock

$value = Cache::lock("rebuild:product:{$id}", 10)->get(function use ($id) {
 return Cache::remember("product:{$id}", 3600, function use ($id) {
 return Product::expensive->find($id);
 });
});

Cache Poisoning

// Do not store user data in public cache
// Wrong:
Cache::put('homepage', view('home', ['user' => auth->user]));

// Correct:
if (!auth->check) {
 Cache::put('homepage:guest', view('home'));
}

Summary

Good caching transforms a slow application into a fast one — often without touching the original code. Start with Query Cache, then Object Cache, and finally Full-Page Cache if needed.


Get Started

Ready to build your project? Configure your cloud server with the specs your app needs, or view plans and pricing.

Share