{"id":"bfdd4524-f6de-4f33-87b6-7c6ec1a9f013","shortId":"gGZxUE","kind":"skill","title":"golang-samber-hot","tagline":"In-memory caching in Golang using samber/hot — eviction algorithms (LRU, LFU, TinyLFU, W-TinyLFU, S3FIFO, ARC, TwoQueue, SIEVE, FIFO), TTL, cache loaders, sharding, stale-while-revalidate, missing key caching, and Prometheus metrics. Apply when using or adopting samber/hot, when ","description":"**Persona:** You are a Go engineer who treats caching as a system design decision. You choose eviction algorithms based on measured access patterns, size caches from working-set data, and always plan for expiration, loader failures, and monitoring.\n\n# Using samber/hot for In-Memory Caching in Go\n\nGeneric, type-safe in-memory caching library for Go 1.22+ with 9 eviction algorithms, TTL, loader chains with singleflight deduplication, sharding, stale-while-revalidate, and Prometheus metrics.\n\n**Official Resources:**\n\n- [pkg.go.dev/github.com/samber/hot](https://pkg.go.dev/github.com/samber/hot)\n- [github.com/samber/hot](https://github.com/samber/hot)\n\nThis skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.\n\n```bash\ngo get -u github.com/samber/hot\n```\n\n## Algorithm Selection\n\nPick based on your access pattern — the wrong algorithm wastes memory or tanks hit rate.\n\n| Algorithm | Constant | Best for | Avoid when |\n| --- | --- | --- | --- |\n| **W-TinyLFU** | `hot.WTinyLFU` | General-purpose, mixed workloads (default) | You need simplicity for debugging |\n| **LRU** | `hot.LRU` | Recency-dominated (sessions, recent queries) | Frequency matters (scan pollution evicts hot items) |\n| **LFU** | `hot.LFU` | Frequency-dominated (popular products, DNS) | Access patterns shift (stale popular items never evict) |\n| **TinyLFU** | `hot.TinyLFU` | Read-heavy with frequency bias | Write-heavy (admission filter overhead) |\n| **S3FIFO** | `hot.S3FIFO` | High throughput, scan-resistant | Small caches (<1000 items) |\n| **ARC** | `hot.ARC` | Self-tuning, unknown patterns | Memory-constrained (2x tracking overhead) |\n| **TwoQueue** | `hot.TwoQueue` | Mixed with hot/cold split | Tuning complexity is unacceptable |\n| **SIEVE** | `hot.SIEVE` | Simple scan-resistant LRU alternative | Highly skewed access patterns |\n| **FIFO** | `hot.FIFO` | Simple, predictable eviction order | Hit rate matters (no frequency/recency awareness) |\n\n**Decision shortcut:** Start with `hot.WTinyLFU`. Switch only when profiling shows the miss rate is too high for your SLO.\n\nFor detailed algorithm comparison, benchmarks, and a decision tree, see [Algorithm Guide](./references/algorithm-guide.md).\n\n## Core Usage\n\n### Basic Cache with TTL\n\n```go\nimport \"github.com/samber/hot\"\n\ncache := hot.NewHotCache[string, *User](hot.WTinyLFU, 10_000).\n    WithTTL(5 * time.Minute).\n    WithJanitor().\n    Build()\ndefer cache.StopJanitor()\n\ncache.Set(\"user:123\", user)\ncache.SetWithTTL(\"session:abc\", session, 30*time.Minute)\n\nvalue, found, err := cache.Get(\"user:123\")\n```\n\n### Loader Pattern (Read-Through)\n\nLoaders fetch missing keys automatically with singleflight deduplication — concurrent `Get()` calls for the same missing key share one loader invocation:\n\n```go\ncache := hot.NewHotCache[int, *User](hot.WTinyLFU, 10_000).\n    WithTTL(5 * time.Minute).\n    WithLoaders(func(ids []int) (map[int]*User, error) {\n        return db.GetUsersByIDs(ctx, ids) // batch query\n    }).\n    WithJanitor().\n    Build()\ndefer cache.StopJanitor()\n\nuser, found, err := cache.Get(123) // triggers loader on miss\n```\n\n## Capacity Sizing\n\nBefore setting the cache capacity, estimate how many items fit in the memory budget:\n\n1. **Estimate single-item size** — estimate size of the struct, add the size of heap-allocated fields (slices, maps, strings). Include the key size. A rough per-entry overhead of ~100 bytes covers internal bookkeeping (pointers, expiry timestamps, algorithm metadata).\n2. **Ask the developer** how much memory is dedicated to this cache in production (e.g., 256 MB, 1 GB). This depends on the service's total memory and what else shares the process.\n3. **Compute capacity** — `capacity = memoryBudget / estimatedItemSize`. Round down to leave headroom.\n\n```\nExample: *User struct ~500 bytes + string key ~50 bytes + overhead ~100 bytes = ~650 bytes/entry\n         256 MB budget → 256_000_000 / 650 ≈ 393,000 items\n```\n\nIf the item size is unknown, ask the developer to measure it with a unit test that allocates N items and checks `runtime.ReadMemStats`. Guessing capacity without measuring leads to OOM or wasted memory.\n\n## Common Mistakes\n\n1. **Forgetting `WithJanitor()`** — without it, expired entries stay in memory until the algorithm evicts them. Always chain `.WithJanitor()` in the builder and `defer cache.StopJanitor()`.\n2. **Calling `SetMissing()` without missing cache config** — panics at runtime. Enable `WithMissingCache(algorithm, capacity)` or `WithMissingSharedCache()` in the builder first.\n3. **`WithoutLocking()` + `WithJanitor()`** — mutually exclusive, panics. `WithoutLocking()` is only safe for single-goroutine access without background cleanup.\n4. **Oversized cache** — a cache holding everything is a map with overhead. Size to your working set (typically 10-20% of total data). Monitor hit rate to validate.\n5. **Ignoring loader errors** — `Get()` returns `(zero, false, err)` on loader failure. Always check `err`, not just `found`.\n\n## Best Practices\n\n1. Always set TTL — unbounded caches serve stale data indefinitely because there is no signal to refresh\n2. Use `WithJitter(lambda, upperBound)` to spread expirations — without jitter, items created together expire together, causing thundering herd on the loader\n3. Monitor with `WithPrometheusMetrics(cacheName)` — hit rate below 80% usually means the cache is undersized or the algorithm is wrong for the workload\n4. Use `WithCopyOnRead(fn)` / `WithCopyOnWrite(fn)` for mutable values — without copies, callers mutate cached objects and corrupt shared state\n\nFor advanced patterns (revalidation, sharding, missing cache, monitoring setup), see [Production Patterns](./references/production-patterns.md).\n\nFor the complete API surface, see [API Reference](./references/api-reference.md).\n\nIf you encounter a bug or unexpected behavior in samber/hot, open an issue at <https://github.com/samber/hot/issues>.\n\n## Cross-References\n\n- → See `samber/cc-skills-golang@golang-performance` skill for general caching strategy and when to use in-memory cache vs Redis vs CDN\n- → See `samber/cc-skills-golang@golang-observability` skill for Prometheus metrics integration and monitoring\n- → See `samber/cc-skills-golang@golang-database` skill for database query patterns that pair with cache loaders\n- → See `samber/cc-skills@promql-cli` skill for querying Prometheus cache metrics via CLI","tags":["golang","samber","hot","skills","agent","agent-skills","antigravity","claude","claude-code","code","codex","coding"],"capabilities":["skill","source-samber","skill-golang-samber-hot","topic-agent","topic-agent-skills","topic-antigravity","topic-claude","topic-claude-code","topic-code","topic-codex","topic-coding","topic-copilot","topic-cursor","topic-gemini","topic-gemini-cli-extension"],"categories":["cc-skills-golang"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/samber/cc-skills-golang/golang-samber-hot","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add samber/cc-skills-golang","source_repo":"https://github.com/samber/cc-skills-golang","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 1725 github stars · SKILL.md body (6,448 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-18T18:53:02.207Z","embedding":null,"createdAt":"2026-04-18T20:32:57.806Z","updatedAt":"2026-05-18T18:53:02.207Z","lastSeenAt":"2026-05-18T18:53:02.207Z","tsv":"'-20':683 '/github.com/samber/hot](https://pkg.go.dev/github.com/samber/hot)':129 '/references/algorithm-guide.md':335 '/references/api-reference.md':813 '/references/production-patterns.md':804 '/samber/hot':162,346 '/samber/hot/issues':830 '/samber/hot](https://github.com/samber/hot)':132 '000':353,409,561,562,565 '1':456,516,602,712 '1.22':106 '10':352,408,682 '100':489,553 '1000':255 '123':363,376,435 '2':499,626,729 '256':514,557,560 '2x':267 '3':532,646,750 '30':369 '393':564 '4':664,773 '5':355,411,692 '50':550 '500':546 '650':555,563 '80':758 '9':108 'abc':367 'access':68,169,224,290,660 'add':467 'admiss':243 'adopt':44 'advanc':793 'algorithm':14,64,110,163,173,180,325,333,497,614,638,767 'alloc':473,584 'altern':287 'alway':78,617,704,713 'api':808,811 'appli':40 'arc':22,257 'ask':500,573 'automat':386 'avoid':184 'awar':303 'background':662 'base':65,166 'bash':156 'basic':338 'batch':425 'behavior':821 'benchmark':327 'best':182,710 'bias':239 'bookkeep':493 'budget':455,559 'bug':818 'build':358,428 'builder':622,644 'byte':490,547,551,554 'bytes/entry':556 'cach':8,27,36,55,71,92,102,254,339,347,403,445,510,631,666,668,717,762,786,798,842,851,881,892 'cache.get':374,434 'cache.set':361 'cache.setwithttl':365 'cache.stopjanitor':360,430,625 'cachenam':754 'call':392,627 'caller':784 'capac':440,446,534,535,591,639 'caus':744 'cdn':855 'chain':113,618 'check':588,705 'choos':62 'cleanup':663 'cli':887,895 'code':144 'common':600 'comparison':326 'complet':807 'complex':277 'comput':533 'concurr':390 'config':632 'constant':181 'constrain':266 'context7':149 'copi':783 'core':336 'corrupt':789 'cover':491 'creat':740 'cross':832 'cross-refer':831 'ctx':423 'data':76,686,720 'databas':872,875 'db.getusersbyids':422 'debug':200 'decis':60,304,330 'dedic':507 'dedupl':116,389 'default':195 'defer':359,429,624 'depend':519 'design':59 'detail':324 'develop':502,575 'discover':154 'dns':223 'document':142 'domin':205,220 'e.g':513 'els':528 'enabl':636 'encount':816 'engin':52 'entri':486,608 'err':373,433,700,706 'error':420,695 'estim':447,457,462 'estimateditems':537 'everyth':670 'evict':13,63,109,213,231,296,615 'exampl':145,543 'exclus':650 'exhaust':137 'expir':81,607,736,742 'expiri':495 'failur':83,703 'fals':699 'fetch':383 'field':474 'fifo':25,292 'filter':244 'first':645 'fit':451 'fn':776,778 'forget':603 'found':372,432,709 'frequenc':209,219,238 'frequency-domin':218 'frequency/recency':302 'func':414 'gb':517 'general':191,841 'general-purpos':190 'generic':95 'get':158,391,696 'github.com':131,161,345,829 'github.com/samber/hot':160,344 'github.com/samber/hot/issues':828 'github.com/samber/hot](https://github.com/samber/hot)':130 'go':51,94,105,157,342,402 'golang':2,10,837,859,871 'golang-databas':870 'golang-observ':858 'golang-perform':836 'golang-samber-hot':1 'goroutin':659 'guess':590 'guid':334 'headroom':542 'heap':472 'heap-alloc':471 'heavi':236,242 'help':151 'herd':746 'high':248,288,319 'hit':178,298,688,755 'hold':669 'hot':4,214 'hot.arc':258 'hot.fifo':293 'hot.lfu':217 'hot.lru':202 'hot.newhotcache':348,404 'hot.s3fifo':247 'hot.sieve':281 'hot.tinylfu':233 'hot.twoqueue':271 'hot.wtinylfu':189,308,351,407 'hot/cold':274 'id':415,424 'ignor':693 'import':343 'in-memori':5,89,99,848 'includ':478 'indefinit':721 'inform':148 'int':405,416,418 'integr':865 'intern':492 'invoc':401 'issu':826 'item':215,229,256,450,460,566,569,586,739 'jitter':738 'key':35,385,397,480,549 'lambda':732 'lead':594 'leav':541 'lfu':16,216 'librari':103,141 'loader':28,82,112,377,382,400,437,694,702,749,882 'lru':15,201,286 'mani':449 'map':417,476,673 'matter':210,300 'mb':515,558 'mean':760 'measur':67,577,593 'memori':7,91,101,175,265,454,505,525,599,611,850 'memory-constrain':264 'memorybudget':536 'metadata':498 'metric':39,124,864,893 'miss':34,315,384,396,439,630,797 'mistak':601 'mix':193,272 'monitor':85,687,751,799,867 'much':504 'mutabl':780 'mutat':785 'mutual':649 'n':585 'need':197 'never':230 'object':787 'observ':860 'offici':125 'one':399 'oom':596 'open':824 'order':297 'overhead':245,269,487,552,675 'overs':665 'pair':879 'panic':633,651 'pattern':69,170,225,263,291,378,794,803,877 'per':485 'per-entri':484 'perform':838 'persona':47 'pick':165 'pkg.go.dev':128 'pkg.go.dev/github.com/samber/hot](https://pkg.go.dev/github.com/samber/hot)':127 'plan':79 'platform':155 'pleas':138 'pointer':494 'pollut':212 'popular':221,228 'practic':711 'predict':295 'process':531 'product':222,512,802 'profil':312 'prometheus':38,123,863,891 'promql':886 'promql-c':885 'purpos':192 'queri':208,426,876,890 'rate':179,299,316,689,756 'read':235,380 'read-heavi':234 'read-through':379 'recenc':204 'recency-domin':203 'recent':207 'redi':853 'refer':139,812,833 'refresh':728 'resist':252,285 'resourc':126 'return':421,697 'revalid':33,121,795 'rough':483 'round':538 'runtim':635 'runtime.readmemstats':589 's3fifo':21,246 'safe':98,655 'samber':3 'samber/cc-skills':884 'samber/cc-skills-golang':835,857,869 'samber/hot':12,45,87,823 'scan':211,251,284 'scan-resist':250,283 'see':332,801,810,834,856,868,883 'select':164 'self':260 'self-tun':259 'serv':718 'servic':522 'session':206,366,368 'set':75,443,680,714 'setmiss':628 'setup':800 'shard':29,117,796 'share':398,529,790 'shift':226 'shortcut':305 'show':313 'siev':24,280 'signal':726 'simpl':282,294 'simplic':198 'singl':459,658 'single-goroutin':657 'single-item':458 'singleflight':115,388 'size':70,441,461,463,469,481,570,676 'skew':289 'skill':134,839,861,873,888 'skill-golang-samber-hot' 'slice':475 'slo':322 'small':253 'source-samber' 'split':275 'spread':735 'stale':31,119,227,719 'stale-while-revalid':30,118 'start':306 'state':791 'stay':609 'strategi':843 'string':349,477,548 'struct':466,545 'surfac':809 'switch':309 'system':58 'tank':177 'test':582 'throughput':249 'thunder':745 'time.minute':356,370,412 'timestamp':496 'tinylfu':17,20,188,232 'togeth':741,743 'topic-agent' 'topic-agent-skills' 'topic-antigravity' 'topic-claude' 'topic-claude-code' 'topic-code' 'topic-codex' 'topic-coding' 'topic-copilot' 'topic-cursor' 'topic-gemini' 'topic-gemini-cli-extension' 'total':524,685 'track':268 'treat':54 'tree':331 'trigger':436 'ttl':26,111,341,715 'tune':261,276 'twoqueu':23,270 'type':97 'type-saf':96 'typic':681 'u':159 'unaccept':279 'unbound':716 'unders':764 'unexpect':820 'unit':581 'unknown':262,572 'upperbound':733 'usag':337 'use':11,42,86,730,774,847 'user':350,362,364,375,406,419,431,544 'usual':759 'valid':691 'valu':371,781 'via':894 'vs':852,854 'w':19,187 'w-tinylfu':18,186 'wast':174,598 'withcopyonread':775 'withcopyonwrit':777 'withjanitor':357,427,604,619,648 'withjitt':731 'withload':413 'withmissingcach':637 'withmissingsharedcach':641 'without':592,605,629,661,737,782 'withoutlock':647,652 'withprometheusmetr':753 'withttl':354,410 'work':74,679 'working-set':73 'workload':194,772 'write':241 'write-heavi':240 'wrong':172,769 'zero':698","prices":[{"id":"aa379f65-23c4-47be-b435-4d4f1ff8ad25","listingId":"bfdd4524-f6de-4f33-87b6-7c6ec1a9f013","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"samber","category":"cc-skills-golang","install_from":"skills.sh"},"createdAt":"2026-04-18T20:32:57.806Z"}],"sources":[{"listingId":"bfdd4524-f6de-4f33-87b6-7c6ec1a9f013","source":"github","sourceId":"samber/cc-skills-golang/golang-samber-hot","sourceUrl":"https://github.com/samber/cc-skills-golang/tree/main/skills/golang-samber-hot","isPrimary":false,"firstSeenAt":"2026-04-18T21:55:18.630Z","lastSeenAt":"2026-05-18T18:53:02.207Z"},{"listingId":"bfdd4524-f6de-4f33-87b6-7c6ec1a9f013","source":"skills_sh","sourceId":"samber/cc-skills-golang/golang-samber-hot","sourceUrl":"https://skills.sh/samber/cc-skills-golang/golang-samber-hot","isPrimary":true,"firstSeenAt":"2026-04-18T20:32:57.806Z","lastSeenAt":"2026-05-07T22:40:28.527Z"}],"details":{"listingId":"bfdd4524-f6de-4f33-87b6-7c6ec1a9f013","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"samber","slug":"golang-samber-hot","github":{"repo":"samber/cc-skills-golang","stars":1725,"topics":["agent","agent-skills","ai","antigravity","claude","claude-code","code","codex","coding","copilot","cursor","gemini","gemini-cli-extension","openclaw","opencode","plugin","skills","skillsmp","vibe-coding"],"license":"mit","html_url":"https://github.com/samber/cc-skills-golang","pushed_at":"2026-05-18T17:36:00Z","description":"🧑‍🎨 A collection of Golang agentic skills that works","skill_md_sha":"fb0fd54f506e1cf242a145156a2f68a04771b01d","skill_md_path":"skills/golang-samber-hot/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/samber/cc-skills-golang/tree/main/skills/golang-samber-hot"},"layout":"multi","source":"github","category":"cc-skills-golang","frontmatter":{"name":"golang-samber-hot","license":"MIT","description":"In-memory caching in Golang using samber/hot — eviction algorithms (LRU, LFU, TinyLFU, W-TinyLFU, S3FIFO, ARC, TwoQueue, SIEVE, FIFO), TTL, cache loaders, sharding, stale-while-revalidate, missing key caching, and Prometheus metrics. Apply when using or adopting samber/hot, when the codebase imports github.com/samber/hot, or when the project repeatedly loads the same medium-to-low cardinality resources at high frequency and needs to reduce latency or backend pressure.","compatibility":"Designed for Claude Code or similar AI coding agents, and for projects using Golang."},"skills_sh_url":"https://skills.sh/samber/cc-skills-golang/golang-samber-hot"},"updatedAt":"2026-05-18T18:53:02.207Z"}}