{"id":"53bc3207-b9dd-4ee4-b7f4-d501cfdcec10","shortId":"CMy7cg","kind":"skill","title":"Caching Strategy Advisor","tagline":"Recommends the right caching layer, TTL strategy, and invalidation approach for any application bottleneck.","description":"# Caching Strategy Advisor\n\n## What this skill does\n\nThis skill analyzes a performance bottleneck, a slow query, or an expensive operation and recommends the right caching strategy for it — which cache layer to use, what TTL to set, how to handle cache invalidation, and what to watch out for. It covers in-memory caches, Redis, HTTP caching headers, CDN caching, and database query caching, and explains the trade-offs of each recommendation.\n\nUse this when you have a slow API, a database that's under heavy read load, a page that's slow to load, or any operation that's expensive and called frequently.\n\n## How to use\n\n### Claude Code / Cline\n\nCopy this file to `.agents/skills/caching-strategy-advisor/SKILL.md` in your project root.\n\nThen ask:\n- *\"Use the Caching Strategy Advisor skill — our product listing API is slow and called thousands of times per minute.\"*\n- *\"We have a heavy database query that runs on every page load. Use the Caching Strategy Advisor skill to recommend a caching approach.\"*\n\nProvide:\n- What operation is slow (SQL query, API call, computation, file read)\n- How often it's called and by how many users\n- How often the underlying data changes\n- Your current tech stack (language, framework, existing infrastructure)\n- What consistency guarantees you need (is stale data for a few seconds OK?)\n\n### Cursor\n\nAdd the instructions below to your `.cursorrules` or paste them into the Cursor AI pane with the context above.\n\n### Codex\n\nProvide the operation description and context. Ask Codex to follow the instructions below to produce the caching recommendation.\n\n## The Prompt / Instructions for the Agent\n\nWhen asked to advise on a caching strategy, follow these steps:\n\n### Step 1 — Understand the workload\n\nAsk or infer:\n- **Read/write ratio**: Is this data mostly read, or is it frequently updated?\n- **Call frequency**: How many requests per second/minute hit this operation?\n- **Data freshness requirement**: How stale can the data be before it causes a real problem? 1 second? 1 minute? 1 hour? Doesn't matter?\n- **Data size**: How large is the response? (Affects cache storage cost and memory limits)\n- **User specificity**: Is the data the same for all users (public), or different per user (personalized)?\n- **Consistency requirement**: Is it OK to serve slightly stale data, or does every user need to see the absolute latest?\n\n### Step 2 — Identify the right cache layer\n\nChoose the appropriate layer(s):\n\n**In-process / in-memory cache** (e.g., a Map or LRU cache in the application itself)\n- Best for: Frequently read, rarely changing data that's the same for all instances. Config values, lookup tables, small datasets.\n- Trade-offs: Lost on restart, not shared across instances, can cause memory pressure if not bounded.\n- Use when: Single-server deployments, data that almost never changes, sub-millisecond latency needed.\n\n**Redis / Memcached** (distributed key-value cache)\n- Best for: Data shared across multiple application instances. User sessions, computed results, rate limit counters, frequently read DB query results.\n- Trade-offs: Additional infrastructure to manage, network hop adds ~1ms latency.\n- Use when: Multi-instance deployments, data shared between requests from different users/servers.\n\n**HTTP response caching (Cache-Control headers)**\n- Best for: REST API responses that don't change per-user. Public endpoints.\n- Trade-offs: Client controls freshness; requires proper `ETag` or `Last-Modified` for conditional requests.\n- Use when: Public API responses, static-ish data served to browsers or API clients.\n\n**CDN caching** (Cloudflare, CloudFront, Fastly)\n- Best for: Static assets, public pages, API responses that are the same for all users globally.\n- Trade-offs: Purging cached content requires a CDN API call; not suitable for personalized data.\n- Use when: High global traffic, static or semi-static public content, reducing origin server load.\n\n**Database query cache / materialized views**\n- Best for: Expensive aggregation queries that are read-heavy.\n- Trade-offs: Must be refreshed on a schedule or trigger; adds complexity to the data layer.\n- Use when: The query result can't be moved to Redis easily, the query runs on a schedule anyway.\n\n### Step 3 — Recommend TTL and invalidation strategy\n\n**TTL (Time-to-live)**\n- For data that rarely changes: 1 hour to 24 hours\n- For data that changes occasionally: 5–15 minutes\n- For data that changes frequently but exact freshness isn't critical: 30–60 seconds\n- For data where you need exact freshness: cache with event-based invalidation (not TTL)\n\n**Invalidation strategies**:\n\n- **TTL-only (lazy expiry)**: Simplest. Cache expires after TTL. Good when stale data for a few minutes is acceptable.\n- **Write-through**: Update the cache at the same time you write to the database. Good consistency, but write path is slower.\n- **Cache-aside (read-through)**: Check cache first; on miss, read from DB and populate cache. Most common pattern.\n- **Event-based invalidation**: When data changes (on DB write, on event), explicitly delete or update the cache key. Needed for strong consistency.\n- **Stale-while-revalidate**: Serve the stale value immediately while refreshing in the background. Great for reducing perceived latency.\n\n### Step 4 — Flag cache-specific risks\n\nAlways check for:\n- **Cache stampede**: Many requests hit the cache at the same time after expiry, all flooding the DB. Mitigation: probabilistic early expiry, mutex/lock on cache refresh.\n- **Cache poisoning**: Attackers inject bad data into the cache. Mitigation: validate data before caching, don't cache error responses.\n- **Thundering herd on cold start**: Cache is empty on startup; all traffic hits DB. Mitigation: warm the cache on startup, use staggered TTLs.\n- **Memory limits**: Unbounded caches grow until the process crashes. Always set a max size and eviction policy.\n- **Sensitive data in cache**: PII or secrets in cache keys or values. Ensure cache is not exposed and keys don't leak user data.\n\n### Step 5 — Format the recommendation\n\n```markdown\n## Caching Strategy Recommendation\n\n### Problem Summary\n[1–2 sentences describing the bottleneck and the key workload characteristics]\n\n### Recommended Strategy\n[Which cache layer(s) to use and why]\n\n### Implementation Plan\n\n#### Cache Layer: [Layer name]\n- **What to cache**: [The exact query result, API response, computed value]\n- **Cache key structure**: `[prefix]:[identifier]` (e.g., `product:list:category:electronics:page:1`)\n- **TTL**: [Value and reasoning]\n- **Invalidation**: [How and when to invalidate]\n- **Storage estimate**: [Approximate size per entry × expected number of entries]\n\n### Code Pattern\n[Pseudocode or real code example showing the cache-aside or write-through pattern]\n\n### Risks and Mitigations\n| Risk | Mitigation |\n|------|-----------|\n| [Risk] | [How to address it] |\n\n### Expected Impact\n[Estimated reduction in DB load, latency improvement, or throughput increase]\n\n### What NOT to cache\n[Any related data that should NOT be cached, and why]\n```\n\n## Example\n\n**Input to Agent:**\n> \"Use the Caching Strategy Advisor skill. Our `GET /api/products` endpoint queries the database for a product catalog (500 products, with category and price info). It's called 2,000 times per minute. Products are updated by staff roughly once per hour. Our stack is Node.js + PostgreSQL + Redis (already available). Stale data for up to 5 minutes is acceptable.\"\n\n**Output from Agent:**\n\n> ## Caching Strategy Recommendation\n>\n> ### Problem Summary\n> The product catalog is read-heavy (2,000 req/min), changes infrequently (~hourly), and can tolerate up to 5 minutes of staleness. This is an ideal candidate for a Redis cache with a TTL-based expiry.\n>\n> ### Recommended Strategy\n> Cache the query result in Redis with a 5-minute TTL. Use a cache-aside pattern: on a cache miss, query PostgreSQL and populate the cache. No event-based invalidation needed given the acceptable staleness window.\n>\n> ### Implementation Plan\n>\n> #### Cache Layer: Redis\n> - **What to cache**: Full serialized response of `GET /api/products` (the array of 500 products with category and price)\n> - **Cache key**: `products:catalog:all` (if no filtering); `products:catalog:category:[slug]` (if filtered by category)\n> - **TTL**: 5 minutes (300 seconds)\n> - **Invalidation**: TTL-only. Optionally: explicitly delete the key after a staff product update for immediate freshness.\n> - **Storage estimate**: ~500 products × ~500 bytes = ~250KB per cache key — well within Redis limits\n>\n> ### Code Pattern\n> ```ts\n> async function getProducts(category?: string): Promise<Product[]> {\n>   const cacheKey = category ? `products:catalog:category:${category}` : 'products:catalog:all';\n>\n>   const cached = await redis.get(cacheKey);\n>   if (cached) return JSON.parse(cached);\n>\n>   const products = await db.query('SELECT * FROM products WHERE ...', [category]);\n>   await redis.setex(cacheKey, 300, JSON.stringify(products)); // TTL: 300s\n>   return products;\n> }\n> ```\n>\n> ### Risks and Mitigations\n>\n> | Risk | Mitigation |\n> |------|-----------|\n> | Cache stampede (all cache keys expire at once) | Add small random jitter to TTL: `300 + Math.floor(Math.random() * 30)` |\n> | Cold start on deploy | Pre-warm cache on server startup by calling `getProducts()` |\n>\n> ### Expected Impact\n> DB read load for this endpoint drops by ~98% (cache miss rate will be very low at 2,000 req/min with 5-minute TTL).\n\n## Notes\n\n- Don't cache what you can't invalidate. If you're not sure how to invalidate a cache entry when the data changes, use a shorter TTL until you have a proper invalidation strategy.\n- Cache the output of expensive operations, not the input. Cache the rendered HTML or the query result, not intermediate variables.\n- Measure before and after — add cache hit/miss metrics so you can verify the cache is actually being used.","tags":["caching","strategy","advisor","openagentskills","notysoty","agent-skills","claude","claude-code","claude-skills","cline","cursor","llm"],"capabilities":["skill","source-notysoty","skill-caching-strategy-advisor","topic-agent-skills","topic-claude","topic-claude-code","topic-claude-skills","topic-cline","topic-cursor","topic-llm","topic-llm-skills","topic-skills"],"categories":["openagentskills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/Notysoty/openagentskills/caching-strategy-advisor","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add Notysoty/openagentskills","source_repo":"https://github.com/Notysoty/openagentskills","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (9,886 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:13:20.974Z","embedding":null,"createdAt":"2026-05-18T13:20:41.435Z","updatedAt":"2026-05-18T19:13:20.974Z","lastSeenAt":"2026-05-18T19:13:20.974Z","tsv":"'/api/products':1110,1258 '000':1130,1176,1426 '1':288,332,334,336,698,975,1024 '15':709 '1ms':510 '2':392,976,1129,1175,1425 '24':701 '250kb':1312 '3':682 '30':722,1391 '300':1287,1362,1388 '300s':1366 '4':847 '5':708,965,1156,1186,1215,1285,1429 '500':1119,1262,1308,1310 '60':723 '98':1416 'absolut':389 'accept':761,1159,1242 'across':448,484 'actual':1502 'add':232,509,656,1382,1491 'addit':503 'address':1070 'advis':279 'advisor':3,20,144,175,1106 'affect':348 'agent':275,1101,1162 'agents/skills/caching-strategy-advisor/skill.md':133 'aggreg':638 'ai':245 'almost':465 'alreadi':1149 'alway':853,932 'analyz':27 'anyway':680 'api':98,149,189,535,565,575,588,607,1009 'applic':16,418,486 'approach':13,181 'appropri':400 'approxim':1037 'array':1260 'asid':786,1056,1222 'ask':139,258,277,292 'asset':585 'async':1323 'attack':883 'avail':1150 'await':1342,1352,1359 'background':840 'bad':885 'base':736,806,1203,1237 'best':420,480,532,582,635 'bottleneck':17,30,980 'bound':456 'browser':573 'byte':1311 'cach':1,7,18,42,47,58,71,74,77,81,142,173,180,268,282,349,396,409,415,479,527,529,578,602,632,732,748,767,785,791,800,821,850,856,862,879,881,889,894,897,905,917,926,943,948,953,970,989,998,1004,1013,1055,1087,1095,1104,1163,1198,1207,1221,1226,1233,1247,1252,1268,1314,1341,1346,1349,1374,1377,1399,1417,1435,1450,1467,1476,1492,1500 'cache-asid':784,1054,1220 'cache-control':528 'cache-specif':849 'cachekey':1331,1344,1361 'call':121,153,190,198,307,608,1128,1404 'candid':1194 'catalog':1118,1170,1271,1277,1334,1338 'categori':1021,1122,1265,1278,1283,1326,1332,1335,1336,1358 'caus':328,451 'cdn':76,577,606 'chang':209,425,467,540,697,706,714,810,1178,1455 'characterist':985 'check':790,854 'choos':398 'claud':126 'client':549,576 'cline':128 'cloudflar':579 'cloudfront':580 'code':127,1045,1050,1320 'codex':251,259 'cold':903,1392 'common':802 'complex':657 'comput':191,490,1011 'condit':560 'config':434 'consist':219,371,778,826 'const':1330,1340,1350 'content':603,625 'context':249,257 'control':530,550 'copi':129 'cost':351 'counter':494 'cover':67 'crash':931 'critic':721 'current':211 'cursor':231,244 'cursorrul':238 'data':208,225,299,317,324,341,359,380,426,463,482,518,570,613,660,694,704,712,726,755,809,886,892,941,963,1090,1152,1454 'databas':79,100,163,630,776,1114 'dataset':439 'db':497,797,812,872,913,1077,1408 'db.query':1353 'delet':817,1295 'deploy':462,517,1395 'describ':978 'descript':255 'differ':367,523 'distribut':475 'doesn':338 'drop':1414 'e.g':410,1018 'earli':875 'easili':673 'electron':1022 'empti':907 'endpoint':545,1111,1413 'ensur':952 'entri':1040,1044,1451 'error':898 'estim':1036,1074,1307 'etag':554 'event':735,805,815,1236 'event-bas':734,804,1235 'everi':168,383 'evict':938 'exact':717,730,1006 'exampl':1051,1098 'exist':216 'expect':1041,1072,1406 'expens':36,119,637,1471 'expir':749,1379 'expiri':746,868,876,1204 'explain':83 'explicit':816,1294 'expos':956 'fast':581 'file':131,192 'filter':1275,1281 'first':792 'flag':848 'flood':870 'follow':261,284 'format':966 'framework':215 'frequenc':308 'frequent':122,305,422,495,715 'fresh':318,551,718,731,1305 'full':1253 'function':1324 'get':1109,1257 'getproduct':1325,1405 'given':1240 'global':597,617 'good':752,777 'great':841 'grow':927 'guarante':220 'handl':57 'header':75,531 'heavi':104,162,644,1174 'herd':901 'high':616 'hit':314,860,912 'hit/miss':1493 'hop':508 'hour':337,699,702,1142,1180 'html':1479 'http':73,525 'ideal':1193 'identifi':393,1017 'immedi':835,1304 'impact':1073,1407 'implement':996,1245 'improv':1080 'in-memori':68,406 'in-process':403 'increas':1083 'infer':294 'info':1125 'infrastructur':217,504 'infrequ':1179 'inject':884 'input':1099,1475 'instanc':433,449,487,516 'instruct':234,263,272 'intermedi':1485 'invalid':12,59,686,737,740,807,1029,1034,1238,1289,1440,1448,1465 'ish':569 'isn':719 'jitter':1385 'json.parse':1348 'json.stringify':1363 'key':477,822,949,958,983,1014,1269,1297,1315,1378 'key-valu':476 'languag':214 'larg':344 'last':557 'last-modifi':556 'latenc':471,511,845,1079 'latest':390 'layer':8,48,397,401,661,990,999,1000,1248 'lazi':745 'leak':961 'limit':354,493,924,1319 'list':148,1020 'live':692 'load':106,113,170,629,1078,1410 'lookup':436 'lost':443 'low':1423 'lru':414 'manag':506 'mani':202,310,858 'map':412 'markdown':969 'materi':633 'math.floor':1389 'math.random':1390 'matter':340 'max':935 'measur':1487 'memcach':474 'memori':70,353,408,452,923 'metric':1494 'millisecond':470 'minut':158,335,710,759,1133,1157,1187,1216,1286,1430 'miss':794,1227,1418 'mitig':873,890,914,1064,1066,1371,1373 'modifi':558 'most':300 'move':670 'multi':515 'multi-inst':514 'multipl':485 'must':648 'mutex/lock':877 'name':1001 'need':222,385,472,729,823,1239 'network':507 'never':466 'node.js':1146 'note':1432 'number':1042 'occasion':707 'off':87,442,502,548,600,647 'often':195,205 'ok':230,375 'oper':37,116,184,254,316,1472 'option':1293 'origin':627 'output':1160,1469 'page':108,169,587,1023 'pane':246 'past':240 'path':781 'pattern':803,1046,1061,1223,1321 'per':157,312,368,542,1039,1132,1141,1313 'per-us':541 'perceiv':844 'perform':29 'person':370,612 'pii':944 'plan':997,1246 'poison':882 'polici':939 'popul':799,1231 'postgresql':1147,1229 'pre':1397 'pre-warm':1396 'prefix':1016 'pressur':453 'price':1124,1267 'probabilist':874 'problem':331,973,1166 'process':405,930 'produc':266 'product':147,1019,1117,1120,1134,1169,1263,1270,1276,1301,1309,1329,1333,1337,1351,1356,1364,1368 'project':136 'promis':1328 'prompt':271 'proper':553,1464 'provid':182,252 'pseudocod':1047 'public':365,544,564,586,624 'purg':601 'queri':33,80,164,188,498,631,639,665,675,1007,1112,1209,1228,1482 'random':1384 'rare':424,696 'rate':492,1419 'ratio':296 're':1443 'read':105,193,301,423,496,643,788,795,1173,1409 'read-heavi':642,1172 'read-through':787 'read/write':295 'real':330,1049 'reason':1028 'recommend':4,39,90,178,269,683,968,972,986,1165,1205 'redi':72,473,672,1148,1197,1212,1249,1318 'redis.get':1343 'redis.setex':1360 'reduc':626,843 'reduct':1075 'refresh':650,837,880 'relat':1089 'render':1478 'req/min':1177,1427 'request':311,521,561,859 'requir':319,372,552,604 'respons':347,526,536,566,589,899,1010,1255 'rest':534 'restart':445 'result':491,499,666,1008,1210,1483 'return':1347,1367 'revalid':830 'right':6,41,395 'risk':852,1062,1065,1067,1369,1372 'root':137 'rough':1139 'run':166,676 'schedul':653,679 'second':229,333,724,1288 'second/minute':313 'secret':946 'see':387 'select':1354 'semi':622 'semi-stat':621 'sensit':940 'sentenc':977 'serial':1254 'serv':377,571,831 'server':461,628,1401 'session':489 'set':54,933 'share':447,483,519 'shorter':1458 'show':1052 'simplest':747 'singl':460 'single-serv':459 'size':342,936,1038 'skill':23,26,145,176,1107 'skill-caching-strategy-advisor' 'slight':378 'slow':32,97,111,151,186 'slower':783 'slug':1279 'small':438,1383 'source-notysoty' 'specif':356,851 'sql':187 'stack':213,1144 'staff':1138,1300 'stagger':921 'stale':224,321,379,754,828,833,1151,1189,1243 'stale-while-revalid':827 'stamped':857,1375 'start':904,1393 'startup':909,919,1402 'static':568,584,619,623 'static-ish':567 'step':286,287,391,681,846,964 'storag':350,1035,1306 'strategi':2,10,19,43,143,174,283,687,741,971,987,1105,1164,1206,1466 'string':1327 'strong':825 'structur':1015 'sub':469 'sub-millisecond':468 'suitabl':610 'summari':974,1167 'sure':1445 'tabl':437 'tech':212 'thousand':154 'throughput':1082 'thunder':900 'time':156,690,771,866,1131 'time-to-l':689 'toler':1183 'topic-agent-skills' 'topic-claude' 'topic-claude-code' 'topic-claude-skills' 'topic-cline' 'topic-cursor' 'topic-llm' 'topic-llm-skills' 'topic-skills' 'trade':86,441,501,547,599,646 'trade-off':85,440,500,546,598,645 'traffic':618,911 'trigger':655 'ts':1322 'ttl':9,52,684,688,739,743,751,1025,1202,1217,1284,1291,1365,1387,1431,1459 'ttl-base':1201 'ttl-on':742,1290 'ttls':922 'unbound':925 'under':207 'understand':289 'updat':306,765,819,1136,1302 'use':50,91,125,140,171,457,512,562,614,662,920,993,1102,1218,1456,1504 'user':203,355,364,369,384,488,543,596,962 'users/servers':524 'valid':891 'valu':435,478,834,951,1012,1026 'variabl':1486 'verifi':1498 'view':634 'warm':915,1398 'watch':63 'well':1316 'window':1244 'within':1317 'workload':291,984 'write':763,773,780,813,1059 'write-through':762,1058","prices":[{"id":"a14857f6-6967-4adc-a232-18b3845226ee","listingId":"53bc3207-b9dd-4ee4-b7f4-d501cfdcec10","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"Notysoty","category":"openagentskills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:20:41.435Z"}],"sources":[{"listingId":"53bc3207-b9dd-4ee4-b7f4-d501cfdcec10","source":"github","sourceId":"Notysoty/openagentskills/caching-strategy-advisor","sourceUrl":"https://github.com/Notysoty/openagentskills/tree/main/skills/caching-strategy-advisor","isPrimary":false,"firstSeenAt":"2026-05-18T13:20:41.435Z","lastSeenAt":"2026-05-18T19:13:20.974Z"}],"details":{"listingId":"53bc3207-b9dd-4ee4-b7f4-d501cfdcec10","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"Notysoty","slug":"caching-strategy-advisor","github":{"repo":"Notysoty/openagentskills","stars":8,"topics":["agent-skills","claude","claude-code","claude-skills","cline","cursor","llm","llm-skills","skills"],"license":"mit","html_url":"https://github.com/Notysoty/openagentskills","pushed_at":"2026-03-28T06:50:19Z","description":"A  community-driven library of reusable AI agent skills for Claude Code, Cursor, Codex, Cline, and more.","skill_md_sha":"08e174ef766c8ee4924de505da93b7dcd37fc739","skill_md_path":"skills/caching-strategy-advisor/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/Notysoty/openagentskills/tree/main/skills/caching-strategy-advisor"},"layout":"multi","source":"github","category":"openagentskills","frontmatter":{"name":"Caching Strategy Advisor","description":"Recommends the right caching layer, TTL strategy, and invalidation approach for any application bottleneck."},"skills_sh_url":"https://skills.sh/Notysoty/openagentskills/caching-strategy-advisor"},"updatedAt":"2026-05-18T19:13:20.974Z"}}