Back to Articles
Web Development Feb 9, 2026 · 7 min read

I spent 3 days debugging a cache bug. Here is what I learned.

Daniel

Software Developer

It started with a support ticket: “Users are seeing old prices.” We had implemented SSR caching. The cache was working. But something was wrong. Let me tell you what happened.

The Setup

We used Next.js with Sircloa (or in production, the typical approach looks like this):

export async function getServerSideProps({ res }) {
res.setHeader('Cache-Control', 'public, max-age=3600');
const data = await fetchProduct();
return { props: { data } };
}

The Bug

After 10 minutes, users started seeing wrong prices. Here’s what went wrong:

1. User A visits at 10:00 - cache miss, fetches fresh data

2. Admin updates price at 10:05

3. User B visits at 10:06 - still gets cached data (10:00)

4. User B sees old price. Support tickets incoming.

The Fix

We needed cache invalidation. There are two approaches:

1. Time-Based (Simpler)

export async function getServerSideProps({ res, req }) {
// Shorter cache for frequently changing data
res.setHeader('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=300');
}

2. On-Demand Invalidation (Better)

Use a tag-based system with on-demand revalidation:

// Fetch with tags
await fetch('/api/products/1', { next: { tags: ['product-1'] } });

// Revalidate when data changes
await fetch('/api/revalidate?tag=product-1');

What I Learned

Cache invalidation is harder than caching itself. If your data changes frequently, don’t cache user-specific or time-sensitive data. It’s not worth the complexity.