Back to Blog
Guide7 min read2026-05-01

Caching Strategies: Browser, CDN, and Application Cache Explained

Learn how browser caching, CDN edge caching, and application-level caching work together to make your web application dramatically faster.

Caching Strategies: Browser, CDN, and Application Cache Explained

Caching is one of the highest-leverage performance optimizations available. Done well, it can reduce server load by 80%, cut response times from hundreds of milliseconds to single-digit milliseconds, and dramatically improve user experience. Done poorly, it serves stale data and causes hard-to-debug bugs. This guide explains each caching layer and how to use them correctly.

The Three Caching Layers

Every web request passes through multiple potential caches before reaching your database:

  1. 1Browser cache — stored on the user's device
  2. 2CDN / edge cache — stored on servers close to the user, globally distributed
  3. 3Application cache — stored in Redis or similar, in your infrastructure

Each layer serves a different purpose and requires different configuration.

Browser Caching

Browsers cache responses based on HTTP headers you control. The two most important headers are Cache-Control and ETag.

# Cache static assets for 1 year (they should be content-hashed)
Cache-Control: public, max-age=31536000, immutable

# Cache HTML for a short time or not at all
Cache-Control: no-cache

# Validate with ETag before using cached version
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d"

Content-hashed filenames are the key technique here. When you build main.a3f2b1.js instead of main.js, the filename changes every time the content changes. This lets you cache the file for a year safely — the URL itself becomes the cache-busting mechanism.

// Vite / webpack generates content hashes automatically
// vite.config.js
export default {
  build: {
    rollupOptions: {
      output: {
        entryFileNames: 'assets/[name].[hash].js',
        chunkFileNames: 'assets/[name].[hash].js',
        assetFileNames: 'assets/[name].[hash].[ext]',
      }
    }
  }
}

CDN Caching

A CDN (Content Delivery Network) caches your content at edge nodes distributed globally. When a user in Singapore requests your site hosted in the US, the CDN serves cached content from an edge node nearby — eliminating transcontinental round-trip latency.

CDNs respect the same Cache-Control headers as browsers, but you can add s-maxage to differentiate CDN TTL from browser TTL:

# Cache for 5 minutes in CDN, but let browser re-validate every request
Cache-Control: public, s-maxage=300, max-age=0, must-revalidate

For API responses that rarely change, CDN caching can be transformative — serving thousands of requests per second from edge without touching your origin.

Application-Level Caching with Redis

Application caching is for expensive operations: database queries, external API calls, computation-heavy aggregations. Redis is the standard tool.

Cache-aside pattern (most common):

async function getUserDashboard(userId) {
  const cacheKey = `dashboard:${userId}`;

  // 1. Check cache
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  // 2. Cache miss — fetch from database
  const data = await db.query(
    'SELECT * FROM dashboard_metrics WHERE user_id = $1',
    [userId]
  );

  // 3. Store in cache with 5-minute TTL
  await redis.setex(cacheKey, 300, JSON.stringify(data));
  return data;
}

Cache invalidation — the hard part. When data changes, you must either invalidate the relevant cache keys or accept that data will be stale until the TTL expires. Two strategies:

  • TTL-based: accept short-lived staleness. Simple, works well for dashboards and reports.
  • Event-based: delete cache keys explicitly when data changes. More complex, always consistent.
// Event-based invalidation on update
async function updateUserProfile(userId, data) {
  await db.query('UPDATE users SET ... WHERE id = $1', [userId]);
  await redis.del(`dashboard:${userId}`); // Invalidate cache immediately
}

Choosing TTL Values

Data TypeSuggested TTL
User session30 minutes (sliding)
Dashboard metrics60–300 seconds
Product catalog10–60 minutes
Static content1 year (content-hashed)
Real-time data0 (do not cache)

What Not to Cache

  • Personalized, user-specific API responses via CDN — without careful Vary headers, one user's data will be served to another
  • Mutation results — POST/PUT/DELETE responses should not be cached
  • Payment or authentication responses — never cache sensitive data

PandaStack and Redis

[PandaStack](https://dashboard.pandastack.io) supports Redis as a managed database alongside PostgreSQL, MySQL, and MongoDB. This means you can provision a Redis instance alongside your application container with no additional infrastructure setup, then use it for session storage, cache-aside caching, and pub/sub — all from the same dashboard.

Summary

Layer your caching strategy:

  1. 1Browser: long TTLs on content-hashed static assets
  2. 2CDN: cache public API responses and pages at the edge
  3. 3Redis: cache expensive database queries and computations

Each layer catches different traffic patterns. Together, they can handle 10× the load of an uncached system with a fraction of the infrastructure cost.

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also