Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Caching strategies — invalidation, TTL guidelines, cache keys, cache layers, and when not to cache. Use when implementing or reviewing caching logic.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 70% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 55% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 35% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 71% | 0% |
staleTime/gcTime for client-side caching.<entity>:<id>:<variant> (e.g., user:123:profile, products:list:page=2).| Layer | Best For | TTL Range | |-------|----------|-----------| | In-memory (Map, LRU) | Hot data, single-instance apps | Seconds to minutes | | Redis / Memcached | Shared cache across instances, sessions | Minutes to hours | | CDN / Edge | Static assets, public API responses | Hours to days | | HTTP cache headers | Browser caching, API responses | Varies by resource |
tsconst cache = new Map<string, { value: unknown; expires: number }>(); const MAX_SIZE = 500; export function getOrSet<T>(key: string, ttlMs: number, compute: () => T): T { const entry = cache.get(key); if (entry && entry.expires > Date.now()) return entry.value as T; const value = compute(); if (cache.size >= MAX_SIZE) { // Evict oldest entry (first inserted) const oldest = cache.keys().next().value!; cache.delete(oldest); } cache.set(key, { value, expires: Date.now() + ttlMs }); return value; }
tsimport Redis from "ioredis"; const redis = new Redis(process.env.REDIS_URL); export async function swr<T>( key: string, freshSec: number, staleSec: number, fetcher: () => Promise<T>, ): Promise<T> { const raw = await redis.get(key); if (raw) { const { value, createdAt } = JSON.parse(raw) as { value: T; createdAt: number }; const ageMs = Date.now() - createdAt; if (ageMs < freshSec * 1000) return value; // Fresh — return immediately if (ageMs < staleSec * 1000) { // Stale — return cached, refresh in background fetcher().then((v) => redis.set(key, JSON.stringify({ value: v, createdAt: Date.now() }), "EX", staleSec), ); return value; } } const value = await fetcher(); await redis.set(key, JSON.stringify({ value, createdAt: Date.now() }), "EX", staleSec); return value; }
ts// Immutable assets (hashed filenames) app.use("/assets", (_, res, next) => { res.setHeader("Cache-Control", "public, max-age=31536000, immutable"); next(); }); // API responses — short cache with revalidation app.get("/api/products", (_, res) => { res.setHeader("Cache-Control", "public, max-age=60, stale-while-revalidate=300"); res.json(products); });
tsximport { QueryClient, QueryClientProvider } from "@tanstack/react-query"; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000, // Data fresh for 5 minutes gcTime: 30 * 60 * 1000, // Garbage-collect after 30 minutes retry: 2, refetchOnWindowFocus: false, }, }, }); // Usage in a component const { data } = useQuery({ queryKey: ["products", { page, category }], // Cache key includes params queryFn: () => fetchProducts({ page, category }), });
products:list:page=2:locale=en.Other measured skills in the registry, with their headline benchmark lift.