cache-invalidation

Cache invalidation — TTL, event-driven, cache-aside, write-through, SWR, tag purge

39 stars

Best use case

cache-invalidation is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Cache invalidation — TTL, event-driven, cache-aside, write-through, SWR, tag purge

Teams using cache-invalidation should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/cache-invalidation/SKILL.md --create-dirs "https://raw.githubusercontent.com/InugamiDev/ultrathink-oss/main/.claude/skills/cache-invalidation/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/cache-invalidation/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How cache-invalidation Compares

Feature / Agentcache-invalidationStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Cache invalidation — TTL, event-driven, cache-aside, write-through, SWR, tag purge

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Cache Invalidation

## Overview

Cache invalidation is the process of removing or updating stale cached data when the underlying source of truth changes. It is famously one of the two hard problems in computer science. The goal is to balance freshness (serving current data) against performance (avoiding unnecessary origin fetches).

## When to Use

- Any system with a caching layer (Redis, CDN, in-memory, browser)
- APIs where data freshness requirements vary by endpoint
- E-commerce catalogs, CMS content, user profiles — data that changes but not on every request
- Multi-tier caches (browser -> CDN -> app cache -> database)

## Key Patterns

### Cache-Aside (Lazy Loading)

Application checks cache first; on miss, reads from DB and populates cache.

```typescript
async function getProduct(id: string): Promise<Product> {
  const cacheKey = `product:${id}`;
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  const product = await db.query('SELECT * FROM products WHERE id = $1', [id]);
  await redis.setex(cacheKey, 3600, JSON.stringify(product)); // 1h TTL
  return product;
}

async function updateProduct(id: string, data: Partial<Product>) {
  await db.query('UPDATE products SET ... WHERE id = $1', [id]);
  await redis.del(`product:${id}`); // invalidate — next read repopulates
}
```

### Write-Through

Write to cache and DB simultaneously. Cache is always fresh but writes are slower.

```typescript
async function updateProduct(id: string, data: Partial<Product>) {
  const updated = await db.query(
    'UPDATE products SET ... WHERE id = $1 RETURNING *', [id]
  );
  await redis.setex(`product:${id}`, 3600, JSON.stringify(updated));
  return updated;
}
```

### Event-Driven Invalidation

Decouple invalidation from the write path using events.

```typescript
// Publisher (in the write service)
await db.query('UPDATE products SET price = $1 WHERE id = $2', [newPrice, id]);
await eventBus.publish('product.updated', { id, fields: ['price'] });

// Subscriber (cache invalidation worker)
eventBus.subscribe('product.updated', async (event) => {
  await redis.del(`product:${event.id}`);
  await cdn.purgeTag(`product-${event.id}`);
});
```

### Tag-Based Purging (CDN / Vercel)

```typescript
// Set tags when caching
// Next.js revalidateTag example
import { revalidateTag } from 'next/cache';

// In a fetch call
fetch('https://api.example.com/products', {
  next: { tags: ['products', `category-${categoryId}`] },
});

// On mutation — purge all caches with this tag
export async function updateCategory(id: string) {
  await db.updateCategory(id);
  revalidateTag(`category-${id}`);
}
```

### Stale-While-Revalidate (SWR)

Serve stale data immediately while refreshing in the background.

```typescript
// HTTP header approach
// Cache-Control: public, max-age=60, stale-while-revalidate=300

// Application-level SWR
async function getWithSWR<T>(key: string, fetcher: () => Promise<T>, ttl: number, swrWindow: number) {
  const entry = await redis.hgetall(`swr:${key}`);

  if (entry.data) {
    const age = Date.now() - Number(entry.timestamp);
    if (age < ttl * 1000) return JSON.parse(entry.data); // fresh

    if (age < (ttl + swrWindow) * 1000) {
      // stale but within SWR window — return stale, refresh async
      refreshInBackground(key, fetcher, ttl);
      return JSON.parse(entry.data);
    }
  }

  // Cache miss or expired beyond SWR window
  const fresh = await fetcher();
  await redis.hset(`swr:${key}`, { data: JSON.stringify(fresh), timestamp: Date.now() });
  return fresh;
}
```

## Pitfalls

- **Delete vs. update race**: Two concurrent writes can leave stale data. Prefer delete-on-write (cache-aside) over set-on-write unless you use versioning.
- **Thundering herd**: When a popular key expires, hundreds of requests hit the DB simultaneously. Use request coalescing or a lock to let one request repopulate.
- **Multi-layer inconsistency**: Browser cache, CDN, and app cache can all hold different versions. Set consistent TTLs and use `Vary` headers correctly.
- **Forgetting related keys**: Updating a product may require invalidating the product key, the category listing, search results, and recommendation caches. Use tag-based invalidation to group related entries.
- **TTL = 0 is not invalidation**: Zero TTL means "always revalidate," not "never cache." Understand the difference between no-cache and no-store.

Related Skills

ultrathink

39
from InugamiDev/ultrathink-oss

UltraThink Workflow OS — 4-layer skill mesh with persistent memory and privacy hooks for complex engineering tasks. Routes prompts through intent detection to activate the right domain skills automatically.

ultrathink_review

39
from InugamiDev/ultrathink-oss

Multi-pass code review powered by UltraThink's quality gate — checks correctness, security (OWASP), performance, readability, and project conventions in a single structured pass.

ultrathink_memory

39
from InugamiDev/ultrathink-oss

Persistent memory system for UltraThink — search, save, and recall project context, decisions, and patterns across sessions using Postgres-backed fuzzy search with synonym expansion.

ui-design

39
from InugamiDev/ultrathink-oss

Comprehensive UI design system: 230+ font pairings, 48 themes, 65 design systems, 23 design languages, 30 UX laws, 14 color systems, Swiss grid, Gestalt principles, Pencil.dev workflow. Inherits ui-ux-pro-max (99 UX rules) + impeccable-frontend-design (anti-AI-slop). Triggers on any design, UI, layout, typography, color, theme, or styling task.

Zod

39
from InugamiDev/ultrathink-oss

> TypeScript-first schema validation with static type inference.

webinar-registration-page

39
from InugamiDev/ultrathink-oss

Build a webinar or live event registration page as a self-contained HTML file with countdown timer, speaker bio, agenda, and registration form. Triggers on: "build a webinar registration page", "create a webinar sign-up page", "event registration landing page", "live training registration page", "workshop sign-up page", "create a webinar page", "build an event page", "free webinar landing page", "live demo registration page", "online event page", "create a registration page for my webinar", "build a training event page".

webhooks

39
from InugamiDev/ultrathink-oss

Webhook design patterns — delivery, retry with exponential backoff, HMAC signature verification, payload validation, idempotency keys

web-workers

39
from InugamiDev/ultrathink-oss

Offload heavy computation from the main thread using Web Workers, SharedWorkers, and Comlink — structured messaging, transferable objects, and off-main-thread architecture patterns

web-vitals

39
from InugamiDev/ultrathink-oss

Core Web Vitals monitoring (LCP, FID, CLS, INP, TTFB), measurement with web-vitals library, reporting to analytics, and optimization strategies for Next.js

web-components

39
from InugamiDev/ultrathink-oss

Native Web Components, custom elements API, Shadow DOM, HTML templates, slots, lifecycle callbacks, and framework-agnostic design patterns

wasm

39
from InugamiDev/ultrathink-oss

WebAssembly integration — Rust to WASM with wasm-pack/wasm-bindgen, WASI, browser usage, server-side WASM, and performance considerations

vue

39
from InugamiDev/ultrathink-oss

Vue 3 Composition API, Nuxt patterns, reactivity system, component architecture, and production development practices