[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-encore-encore-go-cache":3,"mdc-qy8u65-key":40,"related-org-encore-encore-go-cache":1261,"related-repo-encore-encore-go-cache":1429},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":27,"repoUrl":28,"updatedAt":29,"license":30,"forks":31,"topics":32,"repo":35,"sourceUrl":38,"mdContent":39},"encore-go-cache","cache data in Redis with Encore Go","Cache data in Redis from Encore Go using `cache.NewCluster` and typed keyspaces from `encore.dev\u002Fstorage\u002Fcache`. Type-safe key\u002Fvalue access with TTLs, atomic increments, and per-keyspace data shapes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"encore","Encore","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fencore.png","encoredev",[13,17,18,21,24],{"name":14,"slug":15,"type":16},"Backend","backend","tag",{"name":9,"slug":8,"type":16},{"name":19,"slug":20,"type":16},"Redis","redis",{"name":22,"slug":23,"type":16},"Caching","caching",{"name":25,"slug":26,"type":16},"Go","go",26,"https:\u002F\u002Fgithub.com\u002Fencoredev\u002Fskills","2026-05-16T05:59:51.499679",null,5,[33,34],"claude-code","skills",{"repoUrl":28,"stars":27,"forks":31,"topics":36,"description":37},[33,34],"Agent Skills for development with Encore.","https:\u002F\u002Fgithub.com\u002Fencoredev\u002Fskills\u002Ftree\u002FHEAD\u002Fencore\u002Fgo-cache","---\nname: encore-go-cache\ndescription: Cache data in Redis from Encore Go using `cache.NewCluster` and typed keyspaces from `encore.dev\u002Fstorage\u002Fcache`. Type-safe key\u002Fvalue access with TTLs, atomic increments, and per-keyspace data shapes.\nwhen_to_use: >-\n  User wants to cache values in a Go service, store ephemeral state, rate-limit by counter, build a leaderboard, speed up a hot read, or store short-lived tokens. Covers `cache.NewCluster`, `cache.NewStringKeyspace`, `cache.NewIntKeyspace`, `cache.NewStructKeyspace`, list\u002Fset keyspaces, TTL helpers (`cache.ExpireIn`, `cache.ExpireDailyAt`, `cache.NeverExpire`), atomic `Increment`\u002F`Decrement`, `SetIfNotExists`, `Replace`, eviction policies, and `cache.Miss`\u002F`cache.KeyExists` errors. Trigger phrases: \"cache this\", \"Redis\", \"key-value store\", \"rate limit\", \"TTL\", \"expire after\", \"in-memory store\", \"session token store\", \"leaderboard counter\".\n---\n\n# Encore Go Caching (Redis)\n\n## Instructions\n\nEncore Go's cache is a typed wrapper around Redis. Declare a `cache.Cluster` once, then create `Keyspace` objects for each shape of data you need.\n\n### Cluster\n\n```go\npackage mycache\n\nimport \"encore.dev\u002Fstorage\u002Fcache\"\n\nvar Cluster = cache.NewCluster(\"my-cache\", cache.ClusterConfig{\n    EvictionPolicy: cache.AllKeysLRU,\n})\n```\n\nEviction policies: `cache.AllKeysLRU` (default), `cache.NoEviction`, `cache.AllKeysLFU`, `cache.AllKeysRandom`, `cache.VolatileLRU`, `cache.VolatileLFU`, `cache.VolatileTTL`, `cache.VolatileRandom`.\n\n### Keyspace types\n\nEach keyspace has a key shape (used to build the Redis key from `KeyPattern`) and a value type.\n\n```go\npackage mycache\n\nimport (\n    \"context\"\n    \"time\"\n    \"encore.dev\u002Fstorage\u002Fcache\"\n)\n\ntype TokenKey struct {\n    TokenID string\n}\n\n\u002F\u002F Strings\nvar Tokens = cache.NewStringKeyspace[TokenKey](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"token\u002F:TokenID\",\n    DefaultExpiry: cache.ExpireIn(time.Hour),\n})\n\nfunc example(ctx context.Context) {\n    _ = Tokens.Set(ctx, TokenKey{TokenID: \"abc\"}, \"value\")\n    val, err := Tokens.Get(ctx, TokenKey{TokenID: \"abc\"}) \u002F\u002F cache.Miss on miss\n    _ = Tokens.Delete(ctx, TokenKey{TokenID: \"abc\"})\n    _ = val\n    _ = err\n}\n```\n\n```go\n\u002F\u002F Integers (atomic counters)\ntype CounterKey struct {\n    UserID string\n}\n\nvar Counters = cache.NewIntKeyspace[CounterKey](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"requests\u002F:UserID\",\n    DefaultExpiry: cache.ExpireIn(10 * time.Second),\n})\n\nfunc incr(ctx context.Context) {\n    count, _ := Counters.Increment(ctx, CounterKey{UserID: \"user123\"}, 1)\n    _, _ = Counters.Decrement(ctx, CounterKey{UserID: \"user123\"}, 1)\n    _ = count\n}\n```\n\n```go\n\u002F\u002F Structs (JSON-encoded)\ntype ProfileKey struct {\n    UserID string\n}\n\ntype UserProfile struct {\n    Name  string\n    Email string\n}\n\nvar Profiles = cache.NewStructKeyspace[ProfileKey, UserProfile](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"profile\u002F:UserID\",\n    DefaultExpiry: cache.ExpireIn(time.Hour),\n})\n\nfunc setProfile(ctx context.Context) {\n    _ = Profiles.Set(ctx, ProfileKey{UserID: \"123\"}, UserProfile{\n        Name: \"Alice\", Email: \"alice@example.com\",\n    })\n}\n```\n\n### Other keyspace types\n\nAll from `encore.dev\u002Fstorage\u002Fcache`:\n\n- `NewFloatKeyspace` — float64 values, has `Increment`.\n- `NewListKeyspace` — list values, with `PushLeft`\u002F`PushRight`\u002F`PopLeft`\u002F`PopRight`\u002F`GetRange`.\n- `NewSetKeyspace` — set values, with `Add`\u002F`Remove`\u002F`Contains`\u002F`Items`.\n\n### Multi-field key patterns\n\n```go\ntype ResourceKey struct {\n    UserID       string\n    ResourcePath string\n}\n\nvar ResourceRequests = cache.NewIntKeyspace[ResourceKey](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"requests\u002F:UserID\u002F:ResourcePath\",\n    DefaultExpiry: cache.ExpireIn(10 * time.Second),\n})\n```\n\n### Expiry helpers\n\n```go\nimport (\n    \"encore.dev\u002Fstorage\u002Fcache\"\n    \"time\"\n)\n\ncache.ExpireIn(time.Hour)              \u002F\u002F relative\ncache.ExpireDailyAt(2, 0, 0, time.UTC) \u002F\u002F specific UTC time each day\ncache.NeverExpire                      \u002F\u002F no expiry\ncache.KeepTTL                          \u002F\u002F keep existing TTL when updating\n```\n\n### Errors\n\n```go\nimport \"encore.dev\u002Fstorage\u002Fcache\"\n\nval, err := keyspace.Get(ctx, key)\nif errors.Is(err, cache.Miss) {\n    \u002F\u002F not in cache\n}\n\nerr = keyspace.SetIfNotExists(ctx, key, value)\nif errors.Is(err, cache.KeyExists) {\n    \u002F\u002F already there\n}\n```\n\n## Guidelines\n\n- Declare `cache.Cluster` and keyspaces as package-level variables.\n- Pick the most specific keyspace type — `IntKeyspace` for counters gives you atomic `Increment`\u002F`Decrement` for free.\n- `Get()` returns `cache.Miss` on miss; `Replace()` and `SetIfNotExists()` return `cache.Miss`\u002F`cache.KeyExists` on conflict.\n- Local development uses an in-memory Redis with a ~100-key cap — don't load-test it.\n- For durable storage, use `encore-go-database` (Postgres) or `encore-go-bucket` (object storage) instead.\n",{"data":41,"body":43},{"name":4,"description":6,"when_to_use":42},"User wants to cache values in a Go service, store ephemeral state, rate-limit by counter, build a leaderboard, speed up a hot read, or store short-lived tokens. Covers `cache.NewCluster`, `cache.NewStringKeyspace`, `cache.NewIntKeyspace`, `cache.NewStructKeyspace`, list\u002Fset keyspaces, TTL helpers (`cache.ExpireIn`, `cache.ExpireDailyAt`, `cache.NeverExpire`), atomic `Increment`\u002F`Decrement`, `SetIfNotExists`, `Replace`, eviction policies, and `cache.Miss`\u002F`cache.KeyExists` errors. Trigger phrases: \"cache this\", \"Redis\", \"key-value store\", \"rate limit\", \"TTL\", \"expire after\", \"in-memory store\", \"session token store\", \"leaderboard counter\".",{"type":44,"children":45},"root",[46,55,62,85,92,166,230,236,249,467,589,747,753,766,875,881,956,962,1036,1042,1132,1138,1255],{"type":47,"tag":48,"props":49,"children":51},"element","h1",{"id":50},"encore-go-caching-redis",[52],{"type":53,"value":54},"text","Encore Go Caching (Redis)",{"type":47,"tag":56,"props":57,"children":59},"h2",{"id":58},"instructions",[60],{"type":53,"value":61},"Instructions",{"type":47,"tag":63,"props":64,"children":65},"p",{},[66,68,75,77,83],{"type":53,"value":67},"Encore Go's cache is a typed wrapper around Redis. Declare a ",{"type":47,"tag":69,"props":70,"children":72},"code",{"className":71},[],[73],{"type":53,"value":74},"cache.Cluster",{"type":53,"value":76}," once, then create ",{"type":47,"tag":69,"props":78,"children":80},{"className":79},[],[81],{"type":53,"value":82},"Keyspace",{"type":53,"value":84}," objects for each shape of data you need.",{"type":47,"tag":86,"props":87,"children":89},"h3",{"id":88},"cluster",[90],{"type":53,"value":91},"Cluster",{"type":47,"tag":93,"props":94,"children":98},"pre",{"className":95,"code":96,"language":26,"meta":97,"style":97},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package mycache\n\nimport \"encore.dev\u002Fstorage\u002Fcache\"\n\nvar Cluster = cache.NewCluster(\"my-cache\", cache.ClusterConfig{\n    EvictionPolicy: cache.AllKeysLRU,\n})\n","",[99],{"type":47,"tag":69,"props":100,"children":101},{"__ignoreMap":97},[102,113,123,132,140,148,157],{"type":47,"tag":103,"props":104,"children":107},"span",{"class":105,"line":106},"line",1,[108],{"type":47,"tag":103,"props":109,"children":110},{},[111],{"type":53,"value":112},"package mycache\n",{"type":47,"tag":103,"props":114,"children":116},{"class":105,"line":115},2,[117],{"type":47,"tag":103,"props":118,"children":120},{"emptyLinePlaceholder":119},true,[121],{"type":53,"value":122},"\n",{"type":47,"tag":103,"props":124,"children":126},{"class":105,"line":125},3,[127],{"type":47,"tag":103,"props":128,"children":129},{},[130],{"type":53,"value":131},"import \"encore.dev\u002Fstorage\u002Fcache\"\n",{"type":47,"tag":103,"props":133,"children":135},{"class":105,"line":134},4,[136],{"type":47,"tag":103,"props":137,"children":138},{"emptyLinePlaceholder":119},[139],{"type":53,"value":122},{"type":47,"tag":103,"props":141,"children":142},{"class":105,"line":31},[143],{"type":47,"tag":103,"props":144,"children":145},{},[146],{"type":53,"value":147},"var Cluster = cache.NewCluster(\"my-cache\", cache.ClusterConfig{\n",{"type":47,"tag":103,"props":149,"children":151},{"class":105,"line":150},6,[152],{"type":47,"tag":103,"props":153,"children":154},{},[155],{"type":53,"value":156},"    EvictionPolicy: cache.AllKeysLRU,\n",{"type":47,"tag":103,"props":158,"children":160},{"class":105,"line":159},7,[161],{"type":47,"tag":103,"props":162,"children":163},{},[164],{"type":53,"value":165},"})\n",{"type":47,"tag":63,"props":167,"children":168},{},[169,171,177,179,185,187,193,194,200,201,207,208,214,215,221,222,228],{"type":53,"value":170},"Eviction policies: ",{"type":47,"tag":69,"props":172,"children":174},{"className":173},[],[175],{"type":53,"value":176},"cache.AllKeysLRU",{"type":53,"value":178}," (default), ",{"type":47,"tag":69,"props":180,"children":182},{"className":181},[],[183],{"type":53,"value":184},"cache.NoEviction",{"type":53,"value":186},", ",{"type":47,"tag":69,"props":188,"children":190},{"className":189},[],[191],{"type":53,"value":192},"cache.AllKeysLFU",{"type":53,"value":186},{"type":47,"tag":69,"props":195,"children":197},{"className":196},[],[198],{"type":53,"value":199},"cache.AllKeysRandom",{"type":53,"value":186},{"type":47,"tag":69,"props":202,"children":204},{"className":203},[],[205],{"type":53,"value":206},"cache.VolatileLRU",{"type":53,"value":186},{"type":47,"tag":69,"props":209,"children":211},{"className":210},[],[212],{"type":53,"value":213},"cache.VolatileLFU",{"type":53,"value":186},{"type":47,"tag":69,"props":216,"children":218},{"className":217},[],[219],{"type":53,"value":220},"cache.VolatileTTL",{"type":53,"value":186},{"type":47,"tag":69,"props":223,"children":225},{"className":224},[],[226],{"type":53,"value":227},"cache.VolatileRandom",{"type":53,"value":229},".",{"type":47,"tag":86,"props":231,"children":233},{"id":232},"keyspace-types",[234],{"type":53,"value":235},"Keyspace types",{"type":47,"tag":63,"props":237,"children":238},{},[239,241,247],{"type":53,"value":240},"Each keyspace has a key shape (used to build the Redis key from ",{"type":47,"tag":69,"props":242,"children":244},{"className":243},[],[245],{"type":53,"value":246},"KeyPattern",{"type":53,"value":248},") and a value type.",{"type":47,"tag":93,"props":250,"children":252},{"className":95,"code":251,"language":26,"meta":97,"style":97},"package mycache\n\nimport (\n    \"context\"\n    \"time\"\n    \"encore.dev\u002Fstorage\u002Fcache\"\n)\n\ntype TokenKey struct {\n    TokenID string\n}\n\n\u002F\u002F Strings\nvar Tokens = cache.NewStringKeyspace[TokenKey](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"token\u002F:TokenID\",\n    DefaultExpiry: cache.ExpireIn(time.Hour),\n})\n\nfunc example(ctx context.Context) {\n    _ = Tokens.Set(ctx, TokenKey{TokenID: \"abc\"}, \"value\")\n    val, err := Tokens.Get(ctx, TokenKey{TokenID: \"abc\"}) \u002F\u002F cache.Miss on miss\n    _ = Tokens.Delete(ctx, TokenKey{TokenID: \"abc\"})\n    _ = val\n    _ = err\n}\n",[253],{"type":47,"tag":69,"props":254,"children":255},{"__ignoreMap":97},[256,263,270,278,286,294,302,310,318,327,336,345,353,362,371,380,389,397,405,414,423,432,441,450,459],{"type":47,"tag":103,"props":257,"children":258},{"class":105,"line":106},[259],{"type":47,"tag":103,"props":260,"children":261},{},[262],{"type":53,"value":112},{"type":47,"tag":103,"props":264,"children":265},{"class":105,"line":115},[266],{"type":47,"tag":103,"props":267,"children":268},{"emptyLinePlaceholder":119},[269],{"type":53,"value":122},{"type":47,"tag":103,"props":271,"children":272},{"class":105,"line":125},[273],{"type":47,"tag":103,"props":274,"children":275},{},[276],{"type":53,"value":277},"import (\n",{"type":47,"tag":103,"props":279,"children":280},{"class":105,"line":134},[281],{"type":47,"tag":103,"props":282,"children":283},{},[284],{"type":53,"value":285},"    \"context\"\n",{"type":47,"tag":103,"props":287,"children":288},{"class":105,"line":31},[289],{"type":47,"tag":103,"props":290,"children":291},{},[292],{"type":53,"value":293},"    \"time\"\n",{"type":47,"tag":103,"props":295,"children":296},{"class":105,"line":150},[297],{"type":47,"tag":103,"props":298,"children":299},{},[300],{"type":53,"value":301},"    \"encore.dev\u002Fstorage\u002Fcache\"\n",{"type":47,"tag":103,"props":303,"children":304},{"class":105,"line":159},[305],{"type":47,"tag":103,"props":306,"children":307},{},[308],{"type":53,"value":309},")\n",{"type":47,"tag":103,"props":311,"children":313},{"class":105,"line":312},8,[314],{"type":47,"tag":103,"props":315,"children":316},{"emptyLinePlaceholder":119},[317],{"type":53,"value":122},{"type":47,"tag":103,"props":319,"children":321},{"class":105,"line":320},9,[322],{"type":47,"tag":103,"props":323,"children":324},{},[325],{"type":53,"value":326},"type TokenKey struct {\n",{"type":47,"tag":103,"props":328,"children":330},{"class":105,"line":329},10,[331],{"type":47,"tag":103,"props":332,"children":333},{},[334],{"type":53,"value":335},"    TokenID string\n",{"type":47,"tag":103,"props":337,"children":339},{"class":105,"line":338},11,[340],{"type":47,"tag":103,"props":341,"children":342},{},[343],{"type":53,"value":344},"}\n",{"type":47,"tag":103,"props":346,"children":348},{"class":105,"line":347},12,[349],{"type":47,"tag":103,"props":350,"children":351},{"emptyLinePlaceholder":119},[352],{"type":53,"value":122},{"type":47,"tag":103,"props":354,"children":356},{"class":105,"line":355},13,[357],{"type":47,"tag":103,"props":358,"children":359},{},[360],{"type":53,"value":361},"\u002F\u002F Strings\n",{"type":47,"tag":103,"props":363,"children":365},{"class":105,"line":364},14,[366],{"type":47,"tag":103,"props":367,"children":368},{},[369],{"type":53,"value":370},"var Tokens = cache.NewStringKeyspace[TokenKey](Cluster, cache.KeyspaceConfig{\n",{"type":47,"tag":103,"props":372,"children":374},{"class":105,"line":373},15,[375],{"type":47,"tag":103,"props":376,"children":377},{},[378],{"type":53,"value":379},"    KeyPattern:    \"token\u002F:TokenID\",\n",{"type":47,"tag":103,"props":381,"children":383},{"class":105,"line":382},16,[384],{"type":47,"tag":103,"props":385,"children":386},{},[387],{"type":53,"value":388},"    DefaultExpiry: cache.ExpireIn(time.Hour),\n",{"type":47,"tag":103,"props":390,"children":392},{"class":105,"line":391},17,[393],{"type":47,"tag":103,"props":394,"children":395},{},[396],{"type":53,"value":165},{"type":47,"tag":103,"props":398,"children":400},{"class":105,"line":399},18,[401],{"type":47,"tag":103,"props":402,"children":403},{"emptyLinePlaceholder":119},[404],{"type":53,"value":122},{"type":47,"tag":103,"props":406,"children":408},{"class":105,"line":407},19,[409],{"type":47,"tag":103,"props":410,"children":411},{},[412],{"type":53,"value":413},"func example(ctx context.Context) {\n",{"type":47,"tag":103,"props":415,"children":417},{"class":105,"line":416},20,[418],{"type":47,"tag":103,"props":419,"children":420},{},[421],{"type":53,"value":422},"    _ = Tokens.Set(ctx, TokenKey{TokenID: \"abc\"}, \"value\")\n",{"type":47,"tag":103,"props":424,"children":426},{"class":105,"line":425},21,[427],{"type":47,"tag":103,"props":428,"children":429},{},[430],{"type":53,"value":431},"    val, err := Tokens.Get(ctx, TokenKey{TokenID: \"abc\"}) \u002F\u002F cache.Miss on miss\n",{"type":47,"tag":103,"props":433,"children":435},{"class":105,"line":434},22,[436],{"type":47,"tag":103,"props":437,"children":438},{},[439],{"type":53,"value":440},"    _ = Tokens.Delete(ctx, TokenKey{TokenID: \"abc\"})\n",{"type":47,"tag":103,"props":442,"children":444},{"class":105,"line":443},23,[445],{"type":47,"tag":103,"props":446,"children":447},{},[448],{"type":53,"value":449},"    _ = val\n",{"type":47,"tag":103,"props":451,"children":453},{"class":105,"line":452},24,[454],{"type":47,"tag":103,"props":455,"children":456},{},[457],{"type":53,"value":458},"    _ = err\n",{"type":47,"tag":103,"props":460,"children":462},{"class":105,"line":461},25,[463],{"type":47,"tag":103,"props":464,"children":465},{},[466],{"type":53,"value":344},{"type":47,"tag":93,"props":468,"children":470},{"className":95,"code":469,"language":26,"meta":97,"style":97},"\u002F\u002F Integers (atomic counters)\ntype CounterKey struct {\n    UserID string\n}\n\nvar Counters = cache.NewIntKeyspace[CounterKey](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"requests\u002F:UserID\",\n    DefaultExpiry: cache.ExpireIn(10 * time.Second),\n})\n\nfunc incr(ctx context.Context) {\n    count, _ := Counters.Increment(ctx, CounterKey{UserID: \"user123\"}, 1)\n    _, _ = Counters.Decrement(ctx, CounterKey{UserID: \"user123\"}, 1)\n    _ = count\n}\n",[471],{"type":47,"tag":69,"props":472,"children":473},{"__ignoreMap":97},[474,482,490,498,505,512,520,528,536,543,550,558,566,574,582],{"type":47,"tag":103,"props":475,"children":476},{"class":105,"line":106},[477],{"type":47,"tag":103,"props":478,"children":479},{},[480],{"type":53,"value":481},"\u002F\u002F Integers (atomic counters)\n",{"type":47,"tag":103,"props":483,"children":484},{"class":105,"line":115},[485],{"type":47,"tag":103,"props":486,"children":487},{},[488],{"type":53,"value":489},"type CounterKey struct {\n",{"type":47,"tag":103,"props":491,"children":492},{"class":105,"line":125},[493],{"type":47,"tag":103,"props":494,"children":495},{},[496],{"type":53,"value":497},"    UserID string\n",{"type":47,"tag":103,"props":499,"children":500},{"class":105,"line":134},[501],{"type":47,"tag":103,"props":502,"children":503},{},[504],{"type":53,"value":344},{"type":47,"tag":103,"props":506,"children":507},{"class":105,"line":31},[508],{"type":47,"tag":103,"props":509,"children":510},{"emptyLinePlaceholder":119},[511],{"type":53,"value":122},{"type":47,"tag":103,"props":513,"children":514},{"class":105,"line":150},[515],{"type":47,"tag":103,"props":516,"children":517},{},[518],{"type":53,"value":519},"var Counters = cache.NewIntKeyspace[CounterKey](Cluster, cache.KeyspaceConfig{\n",{"type":47,"tag":103,"props":521,"children":522},{"class":105,"line":159},[523],{"type":47,"tag":103,"props":524,"children":525},{},[526],{"type":53,"value":527},"    KeyPattern:    \"requests\u002F:UserID\",\n",{"type":47,"tag":103,"props":529,"children":530},{"class":105,"line":312},[531],{"type":47,"tag":103,"props":532,"children":533},{},[534],{"type":53,"value":535},"    DefaultExpiry: cache.ExpireIn(10 * time.Second),\n",{"type":47,"tag":103,"props":537,"children":538},{"class":105,"line":320},[539],{"type":47,"tag":103,"props":540,"children":541},{},[542],{"type":53,"value":165},{"type":47,"tag":103,"props":544,"children":545},{"class":105,"line":329},[546],{"type":47,"tag":103,"props":547,"children":548},{"emptyLinePlaceholder":119},[549],{"type":53,"value":122},{"type":47,"tag":103,"props":551,"children":552},{"class":105,"line":338},[553],{"type":47,"tag":103,"props":554,"children":555},{},[556],{"type":53,"value":557},"func incr(ctx context.Context) {\n",{"type":47,"tag":103,"props":559,"children":560},{"class":105,"line":347},[561],{"type":47,"tag":103,"props":562,"children":563},{},[564],{"type":53,"value":565},"    count, _ := Counters.Increment(ctx, CounterKey{UserID: \"user123\"}, 1)\n",{"type":47,"tag":103,"props":567,"children":568},{"class":105,"line":355},[569],{"type":47,"tag":103,"props":570,"children":571},{},[572],{"type":53,"value":573},"    _, _ = Counters.Decrement(ctx, CounterKey{UserID: \"user123\"}, 1)\n",{"type":47,"tag":103,"props":575,"children":576},{"class":105,"line":364},[577],{"type":47,"tag":103,"props":578,"children":579},{},[580],{"type":53,"value":581},"    _ = count\n",{"type":47,"tag":103,"props":583,"children":584},{"class":105,"line":373},[585],{"type":47,"tag":103,"props":586,"children":587},{},[588],{"type":53,"value":344},{"type":47,"tag":93,"props":590,"children":592},{"className":95,"code":591,"language":26,"meta":97,"style":97},"\u002F\u002F Structs (JSON-encoded)\ntype ProfileKey struct {\n    UserID string\n}\n\ntype UserProfile struct {\n    Name  string\n    Email string\n}\n\nvar Profiles = cache.NewStructKeyspace[ProfileKey, UserProfile](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"profile\u002F:UserID\",\n    DefaultExpiry: cache.ExpireIn(time.Hour),\n})\n\nfunc setProfile(ctx context.Context) {\n    _ = Profiles.Set(ctx, ProfileKey{UserID: \"123\"}, UserProfile{\n        Name: \"Alice\", Email: \"alice@example.com\",\n    })\n}\n",[593],{"type":47,"tag":69,"props":594,"children":595},{"__ignoreMap":97},[596,604,612,619,626,633,641,649,657,664,671,679,687,694,701,708,716,724,732,740],{"type":47,"tag":103,"props":597,"children":598},{"class":105,"line":106},[599],{"type":47,"tag":103,"props":600,"children":601},{},[602],{"type":53,"value":603},"\u002F\u002F Structs (JSON-encoded)\n",{"type":47,"tag":103,"props":605,"children":606},{"class":105,"line":115},[607],{"type":47,"tag":103,"props":608,"children":609},{},[610],{"type":53,"value":611},"type ProfileKey struct {\n",{"type":47,"tag":103,"props":613,"children":614},{"class":105,"line":125},[615],{"type":47,"tag":103,"props":616,"children":617},{},[618],{"type":53,"value":497},{"type":47,"tag":103,"props":620,"children":621},{"class":105,"line":134},[622],{"type":47,"tag":103,"props":623,"children":624},{},[625],{"type":53,"value":344},{"type":47,"tag":103,"props":627,"children":628},{"class":105,"line":31},[629],{"type":47,"tag":103,"props":630,"children":631},{"emptyLinePlaceholder":119},[632],{"type":53,"value":122},{"type":47,"tag":103,"props":634,"children":635},{"class":105,"line":150},[636],{"type":47,"tag":103,"props":637,"children":638},{},[639],{"type":53,"value":640},"type UserProfile struct {\n",{"type":47,"tag":103,"props":642,"children":643},{"class":105,"line":159},[644],{"type":47,"tag":103,"props":645,"children":646},{},[647],{"type":53,"value":648},"    Name  string\n",{"type":47,"tag":103,"props":650,"children":651},{"class":105,"line":312},[652],{"type":47,"tag":103,"props":653,"children":654},{},[655],{"type":53,"value":656},"    Email string\n",{"type":47,"tag":103,"props":658,"children":659},{"class":105,"line":320},[660],{"type":47,"tag":103,"props":661,"children":662},{},[663],{"type":53,"value":344},{"type":47,"tag":103,"props":665,"children":666},{"class":105,"line":329},[667],{"type":47,"tag":103,"props":668,"children":669},{"emptyLinePlaceholder":119},[670],{"type":53,"value":122},{"type":47,"tag":103,"props":672,"children":673},{"class":105,"line":338},[674],{"type":47,"tag":103,"props":675,"children":676},{},[677],{"type":53,"value":678},"var Profiles = cache.NewStructKeyspace[ProfileKey, UserProfile](Cluster, cache.KeyspaceConfig{\n",{"type":47,"tag":103,"props":680,"children":681},{"class":105,"line":347},[682],{"type":47,"tag":103,"props":683,"children":684},{},[685],{"type":53,"value":686},"    KeyPattern:    \"profile\u002F:UserID\",\n",{"type":47,"tag":103,"props":688,"children":689},{"class":105,"line":355},[690],{"type":47,"tag":103,"props":691,"children":692},{},[693],{"type":53,"value":388},{"type":47,"tag":103,"props":695,"children":696},{"class":105,"line":364},[697],{"type":47,"tag":103,"props":698,"children":699},{},[700],{"type":53,"value":165},{"type":47,"tag":103,"props":702,"children":703},{"class":105,"line":373},[704],{"type":47,"tag":103,"props":705,"children":706},{"emptyLinePlaceholder":119},[707],{"type":53,"value":122},{"type":47,"tag":103,"props":709,"children":710},{"class":105,"line":382},[711],{"type":47,"tag":103,"props":712,"children":713},{},[714],{"type":53,"value":715},"func setProfile(ctx context.Context) {\n",{"type":47,"tag":103,"props":717,"children":718},{"class":105,"line":391},[719],{"type":47,"tag":103,"props":720,"children":721},{},[722],{"type":53,"value":723},"    _ = Profiles.Set(ctx, ProfileKey{UserID: \"123\"}, UserProfile{\n",{"type":47,"tag":103,"props":725,"children":726},{"class":105,"line":399},[727],{"type":47,"tag":103,"props":728,"children":729},{},[730],{"type":53,"value":731},"        Name: \"Alice\", Email: \"alice@example.com\",\n",{"type":47,"tag":103,"props":733,"children":734},{"class":105,"line":407},[735],{"type":47,"tag":103,"props":736,"children":737},{},[738],{"type":53,"value":739},"    })\n",{"type":47,"tag":103,"props":741,"children":742},{"class":105,"line":416},[743],{"type":47,"tag":103,"props":744,"children":745},{},[746],{"type":53,"value":344},{"type":47,"tag":86,"props":748,"children":750},{"id":749},"other-keyspace-types",[751],{"type":53,"value":752},"Other keyspace types",{"type":47,"tag":63,"props":754,"children":755},{},[756,758,764],{"type":53,"value":757},"All from ",{"type":47,"tag":69,"props":759,"children":761},{"className":760},[],[762],{"type":53,"value":763},"encore.dev\u002Fstorage\u002Fcache",{"type":53,"value":765},":",{"type":47,"tag":767,"props":768,"children":769},"ul",{},[770,789,836],{"type":47,"tag":771,"props":772,"children":773},"li",{},[774,780,782,788],{"type":47,"tag":69,"props":775,"children":777},{"className":776},[],[778],{"type":53,"value":779},"NewFloatKeyspace",{"type":53,"value":781}," — float64 values, has ",{"type":47,"tag":69,"props":783,"children":785},{"className":784},[],[786],{"type":53,"value":787},"Increment",{"type":53,"value":229},{"type":47,"tag":771,"props":790,"children":791},{},[792,798,800,806,808,814,815,821,822,828,829,835],{"type":47,"tag":69,"props":793,"children":795},{"className":794},[],[796],{"type":53,"value":797},"NewListKeyspace",{"type":53,"value":799}," — list values, with ",{"type":47,"tag":69,"props":801,"children":803},{"className":802},[],[804],{"type":53,"value":805},"PushLeft",{"type":53,"value":807},"\u002F",{"type":47,"tag":69,"props":809,"children":811},{"className":810},[],[812],{"type":53,"value":813},"PushRight",{"type":53,"value":807},{"type":47,"tag":69,"props":816,"children":818},{"className":817},[],[819],{"type":53,"value":820},"PopLeft",{"type":53,"value":807},{"type":47,"tag":69,"props":823,"children":825},{"className":824},[],[826],{"type":53,"value":827},"PopRight",{"type":53,"value":807},{"type":47,"tag":69,"props":830,"children":832},{"className":831},[],[833],{"type":53,"value":834},"GetRange",{"type":53,"value":229},{"type":47,"tag":771,"props":837,"children":838},{},[839,845,847,853,854,860,861,867,868,874],{"type":47,"tag":69,"props":840,"children":842},{"className":841},[],[843],{"type":53,"value":844},"NewSetKeyspace",{"type":53,"value":846}," — set values, with ",{"type":47,"tag":69,"props":848,"children":850},{"className":849},[],[851],{"type":53,"value":852},"Add",{"type":53,"value":807},{"type":47,"tag":69,"props":855,"children":857},{"className":856},[],[858],{"type":53,"value":859},"Remove",{"type":53,"value":807},{"type":47,"tag":69,"props":862,"children":864},{"className":863},[],[865],{"type":53,"value":866},"Contains",{"type":53,"value":807},{"type":47,"tag":69,"props":869,"children":871},{"className":870},[],[872],{"type":53,"value":873},"Items",{"type":53,"value":229},{"type":47,"tag":86,"props":876,"children":878},{"id":877},"multi-field-key-patterns",[879],{"type":53,"value":880},"Multi-field key patterns",{"type":47,"tag":93,"props":882,"children":884},{"className":95,"code":883,"language":26,"meta":97,"style":97},"type ResourceKey struct {\n    UserID       string\n    ResourcePath string\n}\n\nvar ResourceRequests = cache.NewIntKeyspace[ResourceKey](Cluster, cache.KeyspaceConfig{\n    KeyPattern:    \"requests\u002F:UserID\u002F:ResourcePath\",\n    DefaultExpiry: cache.ExpireIn(10 * time.Second),\n})\n",[885],{"type":47,"tag":69,"props":886,"children":887},{"__ignoreMap":97},[888,896,904,912,919,926,934,942,949],{"type":47,"tag":103,"props":889,"children":890},{"class":105,"line":106},[891],{"type":47,"tag":103,"props":892,"children":893},{},[894],{"type":53,"value":895},"type ResourceKey struct {\n",{"type":47,"tag":103,"props":897,"children":898},{"class":105,"line":115},[899],{"type":47,"tag":103,"props":900,"children":901},{},[902],{"type":53,"value":903},"    UserID       string\n",{"type":47,"tag":103,"props":905,"children":906},{"class":105,"line":125},[907],{"type":47,"tag":103,"props":908,"children":909},{},[910],{"type":53,"value":911},"    ResourcePath string\n",{"type":47,"tag":103,"props":913,"children":914},{"class":105,"line":134},[915],{"type":47,"tag":103,"props":916,"children":917},{},[918],{"type":53,"value":344},{"type":47,"tag":103,"props":920,"children":921},{"class":105,"line":31},[922],{"type":47,"tag":103,"props":923,"children":924},{"emptyLinePlaceholder":119},[925],{"type":53,"value":122},{"type":47,"tag":103,"props":927,"children":928},{"class":105,"line":150},[929],{"type":47,"tag":103,"props":930,"children":931},{},[932],{"type":53,"value":933},"var ResourceRequests = cache.NewIntKeyspace[ResourceKey](Cluster, cache.KeyspaceConfig{\n",{"type":47,"tag":103,"props":935,"children":936},{"class":105,"line":159},[937],{"type":47,"tag":103,"props":938,"children":939},{},[940],{"type":53,"value":941},"    KeyPattern:    \"requests\u002F:UserID\u002F:ResourcePath\",\n",{"type":47,"tag":103,"props":943,"children":944},{"class":105,"line":312},[945],{"type":47,"tag":103,"props":946,"children":947},{},[948],{"type":53,"value":535},{"type":47,"tag":103,"props":950,"children":951},{"class":105,"line":320},[952],{"type":47,"tag":103,"props":953,"children":954},{},[955],{"type":53,"value":165},{"type":47,"tag":86,"props":957,"children":959},{"id":958},"expiry-helpers",[960],{"type":53,"value":961},"Expiry helpers",{"type":47,"tag":93,"props":963,"children":965},{"className":95,"code":964,"language":26,"meta":97,"style":97},"import (\n    \"encore.dev\u002Fstorage\u002Fcache\"\n    \"time\"\n)\n\ncache.ExpireIn(time.Hour)              \u002F\u002F relative\ncache.ExpireDailyAt(2, 0, 0, time.UTC) \u002F\u002F specific UTC time each day\ncache.NeverExpire                      \u002F\u002F no expiry\ncache.KeepTTL                          \u002F\u002F keep existing TTL when updating\n",[966],{"type":47,"tag":69,"props":967,"children":968},{"__ignoreMap":97},[969,976,983,990,997,1004,1012,1020,1028],{"type":47,"tag":103,"props":970,"children":971},{"class":105,"line":106},[972],{"type":47,"tag":103,"props":973,"children":974},{},[975],{"type":53,"value":277},{"type":47,"tag":103,"props":977,"children":978},{"class":105,"line":115},[979],{"type":47,"tag":103,"props":980,"children":981},{},[982],{"type":53,"value":301},{"type":47,"tag":103,"props":984,"children":985},{"class":105,"line":125},[986],{"type":47,"tag":103,"props":987,"children":988},{},[989],{"type":53,"value":293},{"type":47,"tag":103,"props":991,"children":992},{"class":105,"line":134},[993],{"type":47,"tag":103,"props":994,"children":995},{},[996],{"type":53,"value":309},{"type":47,"tag":103,"props":998,"children":999},{"class":105,"line":31},[1000],{"type":47,"tag":103,"props":1001,"children":1002},{"emptyLinePlaceholder":119},[1003],{"type":53,"value":122},{"type":47,"tag":103,"props":1005,"children":1006},{"class":105,"line":150},[1007],{"type":47,"tag":103,"props":1008,"children":1009},{},[1010],{"type":53,"value":1011},"cache.ExpireIn(time.Hour)              \u002F\u002F relative\n",{"type":47,"tag":103,"props":1013,"children":1014},{"class":105,"line":159},[1015],{"type":47,"tag":103,"props":1016,"children":1017},{},[1018],{"type":53,"value":1019},"cache.ExpireDailyAt(2, 0, 0, time.UTC) \u002F\u002F specific UTC time each day\n",{"type":47,"tag":103,"props":1021,"children":1022},{"class":105,"line":312},[1023],{"type":47,"tag":103,"props":1024,"children":1025},{},[1026],{"type":53,"value":1027},"cache.NeverExpire                      \u002F\u002F no expiry\n",{"type":47,"tag":103,"props":1029,"children":1030},{"class":105,"line":320},[1031],{"type":47,"tag":103,"props":1032,"children":1033},{},[1034],{"type":53,"value":1035},"cache.KeepTTL                          \u002F\u002F keep existing TTL when updating\n",{"type":47,"tag":86,"props":1037,"children":1039},{"id":1038},"errors",[1040],{"type":53,"value":1041},"Errors",{"type":47,"tag":93,"props":1043,"children":1045},{"className":95,"code":1044,"language":26,"meta":97,"style":97},"import \"encore.dev\u002Fstorage\u002Fcache\"\n\nval, err := keyspace.Get(ctx, key)\nif errors.Is(err, cache.Miss) {\n    \u002F\u002F not in cache\n}\n\nerr = keyspace.SetIfNotExists(ctx, key, value)\nif errors.Is(err, cache.KeyExists) {\n    \u002F\u002F already there\n}\n",[1046],{"type":47,"tag":69,"props":1047,"children":1048},{"__ignoreMap":97},[1049,1056,1063,1071,1079,1087,1094,1101,1109,1117,1125],{"type":47,"tag":103,"props":1050,"children":1051},{"class":105,"line":106},[1052],{"type":47,"tag":103,"props":1053,"children":1054},{},[1055],{"type":53,"value":131},{"type":47,"tag":103,"props":1057,"children":1058},{"class":105,"line":115},[1059],{"type":47,"tag":103,"props":1060,"children":1061},{"emptyLinePlaceholder":119},[1062],{"type":53,"value":122},{"type":47,"tag":103,"props":1064,"children":1065},{"class":105,"line":125},[1066],{"type":47,"tag":103,"props":1067,"children":1068},{},[1069],{"type":53,"value":1070},"val, err := keyspace.Get(ctx, key)\n",{"type":47,"tag":103,"props":1072,"children":1073},{"class":105,"line":134},[1074],{"type":47,"tag":103,"props":1075,"children":1076},{},[1077],{"type":53,"value":1078},"if errors.Is(err, cache.Miss) {\n",{"type":47,"tag":103,"props":1080,"children":1081},{"class":105,"line":31},[1082],{"type":47,"tag":103,"props":1083,"children":1084},{},[1085],{"type":53,"value":1086},"    \u002F\u002F not in cache\n",{"type":47,"tag":103,"props":1088,"children":1089},{"class":105,"line":150},[1090],{"type":47,"tag":103,"props":1091,"children":1092},{},[1093],{"type":53,"value":344},{"type":47,"tag":103,"props":1095,"children":1096},{"class":105,"line":159},[1097],{"type":47,"tag":103,"props":1098,"children":1099},{"emptyLinePlaceholder":119},[1100],{"type":53,"value":122},{"type":47,"tag":103,"props":1102,"children":1103},{"class":105,"line":312},[1104],{"type":47,"tag":103,"props":1105,"children":1106},{},[1107],{"type":53,"value":1108},"err = keyspace.SetIfNotExists(ctx, key, value)\n",{"type":47,"tag":103,"props":1110,"children":1111},{"class":105,"line":320},[1112],{"type":47,"tag":103,"props":1113,"children":1114},{},[1115],{"type":53,"value":1116},"if errors.Is(err, cache.KeyExists) {\n",{"type":47,"tag":103,"props":1118,"children":1119},{"class":105,"line":329},[1120],{"type":47,"tag":103,"props":1121,"children":1122},{},[1123],{"type":53,"value":1124},"    \u002F\u002F already there\n",{"type":47,"tag":103,"props":1126,"children":1127},{"class":105,"line":338},[1128],{"type":47,"tag":103,"props":1129,"children":1130},{},[1131],{"type":53,"value":344},{"type":47,"tag":56,"props":1133,"children":1135},{"id":1134},"guidelines",[1136],{"type":53,"value":1137},"Guidelines",{"type":47,"tag":767,"props":1139,"children":1140},{},[1141,1153,1180,1229,1234],{"type":47,"tag":771,"props":1142,"children":1143},{},[1144,1146,1151],{"type":53,"value":1145},"Declare ",{"type":47,"tag":69,"props":1147,"children":1149},{"className":1148},[],[1150],{"type":53,"value":74},{"type":53,"value":1152}," and keyspaces as package-level variables.",{"type":47,"tag":771,"props":1154,"children":1155},{},[1156,1158,1164,1166,1171,1172,1178],{"type":53,"value":1157},"Pick the most specific keyspace type — ",{"type":47,"tag":69,"props":1159,"children":1161},{"className":1160},[],[1162],{"type":53,"value":1163},"IntKeyspace",{"type":53,"value":1165}," for counters gives you atomic ",{"type":47,"tag":69,"props":1167,"children":1169},{"className":1168},[],[1170],{"type":53,"value":787},{"type":53,"value":807},{"type":47,"tag":69,"props":1173,"children":1175},{"className":1174},[],[1176],{"type":53,"value":1177},"Decrement",{"type":53,"value":1179}," for free.",{"type":47,"tag":771,"props":1181,"children":1182},{},[1183,1189,1191,1197,1199,1205,1207,1213,1215,1220,1221,1227],{"type":47,"tag":69,"props":1184,"children":1186},{"className":1185},[],[1187],{"type":53,"value":1188},"Get()",{"type":53,"value":1190}," returns ",{"type":47,"tag":69,"props":1192,"children":1194},{"className":1193},[],[1195],{"type":53,"value":1196},"cache.Miss",{"type":53,"value":1198}," on miss; ",{"type":47,"tag":69,"props":1200,"children":1202},{"className":1201},[],[1203],{"type":53,"value":1204},"Replace()",{"type":53,"value":1206}," and ",{"type":47,"tag":69,"props":1208,"children":1210},{"className":1209},[],[1211],{"type":53,"value":1212},"SetIfNotExists()",{"type":53,"value":1214}," return ",{"type":47,"tag":69,"props":1216,"children":1218},{"className":1217},[],[1219],{"type":53,"value":1196},{"type":53,"value":807},{"type":47,"tag":69,"props":1222,"children":1224},{"className":1223},[],[1225],{"type":53,"value":1226},"cache.KeyExists",{"type":53,"value":1228}," on conflict.",{"type":47,"tag":771,"props":1230,"children":1231},{},[1232],{"type":53,"value":1233},"Local development uses an in-memory Redis with a ~100-key cap — don't load-test it.",{"type":47,"tag":771,"props":1235,"children":1236},{},[1237,1239,1245,1247,1253],{"type":53,"value":1238},"For durable storage, use ",{"type":47,"tag":69,"props":1240,"children":1242},{"className":1241},[],[1243],{"type":53,"value":1244},"encore-go-database",{"type":53,"value":1246}," (Postgres) or ",{"type":47,"tag":69,"props":1248,"children":1250},{"className":1249},[],[1251],{"type":53,"value":1252},"encore-go-bucket",{"type":53,"value":1254}," (object storage) instead.",{"type":47,"tag":1256,"props":1257,"children":1258},"style",{},[1259],{"type":53,"value":1260},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1262,"total":1428},[1263,1277,1289,1305,1317,1329,1345,1360,1377,1394,1404,1415],{"slug":1264,"name":1264,"fn":1265,"description":1266,"org":1267,"tags":1268,"stars":27,"repoUrl":28,"updatedAt":1276},"encore-api","build type-safe APIs with Encore","Define typed API endpoints in Encore.ts using `api(...)` from `encore.dev\u002Fapi`. Covers typed request\u002Fresponse interfaces, path\u002Fquery\u002Fheader\u002Fcookie params, request validation, and `APIError`. For raw endpoints (`api.raw()`) and inbound webhooks, use `encore-webhook` instead.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1269,1272,1273],{"name":1270,"slug":1271,"type":16},"API Development","api-development",{"name":9,"slug":8,"type":16},{"name":1274,"slug":1275,"type":16},"TypeScript","typescript","2026-04-06T18:09:46.044101",{"slug":1278,"name":1278,"fn":1279,"description":1280,"org":1281,"tags":1282,"stars":27,"repoUrl":28,"updatedAt":1288},"encore-auth","implement Encore.ts authentication","Protect Encore.ts endpoints with authentication and authorize callers. Covers `authHandler`, `Gateway`, `getAuthData`, and `auth: true`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1283,1286,1287],{"name":1284,"slug":1285,"type":16},"Auth","auth",{"name":9,"slug":8,"type":16},{"name":1274,"slug":1275,"type":16},"2026-04-06T18:09:47.336322",{"slug":1290,"name":1290,"fn":1291,"description":1292,"org":1293,"tags":1294,"stars":27,"repoUrl":28,"updatedAt":1304},"encore-bucket","store files in Encore.ts buckets","Store unstructured files in Encore.ts using `Bucket` from `encore.dev\u002Fstorage\u002Fobjects` — uploads, images, documents, blobs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1295,1296,1297,1300,1303],{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":1298,"slug":1299,"type":16},"File Storage","file-storage",{"name":1301,"slug":1302,"type":16},"File Uploads","file-uploads",{"name":1274,"slug":1275,"type":16},"2026-05-16T05:59:52.813772",{"slug":1306,"name":1306,"fn":1307,"description":1308,"org":1309,"tags":1310,"stars":27,"repoUrl":28,"updatedAt":1316},"encore-cache","cache data in Redis with Encore.ts","Cache data in Redis from Encore.ts using `CacheCluster` and typed keyspaces from `encore.dev\u002Fstorage\u002Fcache`. Type-safe key\u002Fvalue access with TTLs, atomic increments, and per-keyspace data shapes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1311,1312,1313,1314,1315],{"name":14,"slug":15,"type":16},{"name":22,"slug":23,"type":16},{"name":9,"slug":8,"type":16},{"name":19,"slug":20,"type":16},{"name":1274,"slug":1275,"type":16},"2026-05-16T05:59:56.808328",{"slug":1318,"name":1318,"fn":1319,"description":1320,"org":1321,"tags":1322,"stars":27,"repoUrl":28,"updatedAt":1328},"encore-code-review","review Encore.ts code","Review existing Encore.ts code for best practices and common anti-patterns.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1323,1326,1327],{"name":1324,"slug":1325,"type":16},"Code Review","code-review",{"name":9,"slug":8,"type":16},{"name":1274,"slug":1275,"type":16},"2026-04-06T18:10:01.123999",{"slug":1330,"name":1330,"fn":1331,"description":1332,"org":1333,"tags":1334,"stars":27,"repoUrl":28,"updatedAt":1344},"encore-cron","schedule recurring jobs in Encore.ts","Schedule periodic \u002F recurring work in Encore.ts using `CronJob` from `encore.dev\u002Fcron`. Covers `every: \"1h\"` interval syntax and `schedule: \"0 9 * * 1\"` cron expressions.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1335,1338,1339,1340,1343],{"name":1336,"slug":1337,"type":16},"Automation","automation",{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":1341,"slug":1342,"type":16},"Scheduling","scheduling",{"name":1274,"slug":1275,"type":16},"2026-05-16T05:59:54.146651",{"slug":1346,"name":1346,"fn":1347,"description":1348,"org":1349,"tags":1350,"stars":27,"repoUrl":28,"updatedAt":1359},"encore-database","build Encore databases","Work with PostgreSQL in Encore.ts using `SQLDatabase` from `encore.dev\u002Fstorage\u002Fsqldb` — schema migrations and SQL queries.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1351,1354,1355,1358],{"name":1352,"slug":1353,"type":16},"Database","database",{"name":9,"slug":8,"type":16},{"name":1356,"slug":1357,"type":16},"ORM","orm",{"name":1274,"slug":1275,"type":16},"2026-04-06T18:09:54.823017",{"slug":1361,"name":1361,"fn":1362,"description":1363,"org":1364,"tags":1365,"stars":27,"repoUrl":28,"updatedAt":1376},"encore-frontend","connect frontend to Encore backend","Connect a frontend application (React, Next.js, Vue, Svelte, etc.) to an Encore.ts backend.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1366,1367,1370,1373],{"name":9,"slug":8,"type":16},{"name":1368,"slug":1369,"type":16},"Frontend","frontend",{"name":1371,"slug":1372,"type":16},"Next.js","next-js",{"name":1374,"slug":1375,"type":16},"React","react","2026-04-06T18:09:56.091006",{"slug":1378,"name":1378,"fn":1379,"description":1380,"org":1381,"tags":1382,"stars":27,"repoUrl":28,"updatedAt":1393},"encore-getting-started","build and run applications with Encore.ts","Bootstrap a brand-new Encore.ts project from zero. Only for first-time CLI install and `encore app create` — not for architecture or feature questions.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1383,1384,1385,1386,1389,1390],{"name":1270,"slug":1271,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":1387,"slug":1388,"type":16},"Local Development","local-development",{"name":1274,"slug":1275,"type":16},{"name":1391,"slug":1392,"type":16},"Web Development","web-development","2026-04-06T18:10:04.885446",{"slug":1395,"name":1395,"fn":1396,"description":1397,"org":1398,"tags":1399,"stars":27,"repoUrl":28,"updatedAt":1403},"encore-go-api","build APIs with Encore Go","Define typed API endpoints in Encore Go using `\u002F\u002Fencore:api` annotations. Covers typed request\u002Fresponse structs, path\u002Fquery\u002Fheader\u002Fcookie params, and error returns. For raw endpoints (`\u002F\u002Fencore:api raw`) and inbound webhooks, use `encore-go-webhook` instead.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1400,1401,1402],{"name":1270,"slug":1271,"type":16},{"name":9,"slug":8,"type":16},{"name":25,"slug":26,"type":16},"2026-04-06T18:09:48.578781",{"slug":1405,"name":1405,"fn":1406,"description":1407,"org":1408,"tags":1409,"stars":27,"repoUrl":28,"updatedAt":1414},"encore-go-auth","implement authentication with Encore Go","Protect Encore Go endpoints with authentication and authorize callers. Covers `auth.AuthHandler`, `auth.UserID`, the `Authorization` header, and `\u002F\u002Fencore:api auth`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1410,1411,1412,1413],{"name":1284,"slug":1285,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":25,"slug":26,"type":16},"2026-04-06T18:09:51.065102",{"slug":1252,"name":1252,"fn":1416,"description":1417,"org":1418,"tags":1419,"stars":27,"repoUrl":28,"updatedAt":1427},"store files in Encore Go buckets","Store unstructured files in Encore Go using `objects.NewBucket` from `encore.dev\u002Fstorage\u002Fobjects` — uploads, images, documents, blobs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1420,1421,1422,1423,1424],{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":1298,"slug":1299,"type":16},{"name":25,"slug":26,"type":16},{"name":1425,"slug":1426,"type":16},"Storage","storage","2026-05-16T06:00:03.633918",28,{"items":1430,"total":1428},[1431,1437,1443,1451,1459,1465,1473],{"slug":1264,"name":1264,"fn":1265,"description":1266,"org":1432,"tags":1433,"stars":27,"repoUrl":28,"updatedAt":1276},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1434,1435,1436],{"name":1270,"slug":1271,"type":16},{"name":9,"slug":8,"type":16},{"name":1274,"slug":1275,"type":16},{"slug":1278,"name":1278,"fn":1279,"description":1280,"org":1438,"tags":1439,"stars":27,"repoUrl":28,"updatedAt":1288},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1440,1441,1442],{"name":1284,"slug":1285,"type":16},{"name":9,"slug":8,"type":16},{"name":1274,"slug":1275,"type":16},{"slug":1290,"name":1290,"fn":1291,"description":1292,"org":1444,"tags":1445,"stars":27,"repoUrl":28,"updatedAt":1304},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1446,1447,1448,1449,1450],{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":1298,"slug":1299,"type":16},{"name":1301,"slug":1302,"type":16},{"name":1274,"slug":1275,"type":16},{"slug":1306,"name":1306,"fn":1307,"description":1308,"org":1452,"tags":1453,"stars":27,"repoUrl":28,"updatedAt":1316},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1454,1455,1456,1457,1458],{"name":14,"slug":15,"type":16},{"name":22,"slug":23,"type":16},{"name":9,"slug":8,"type":16},{"name":19,"slug":20,"type":16},{"name":1274,"slug":1275,"type":16},{"slug":1318,"name":1318,"fn":1319,"description":1320,"org":1460,"tags":1461,"stars":27,"repoUrl":28,"updatedAt":1328},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1462,1463,1464],{"name":1324,"slug":1325,"type":16},{"name":9,"slug":8,"type":16},{"name":1274,"slug":1275,"type":16},{"slug":1330,"name":1330,"fn":1331,"description":1332,"org":1466,"tags":1467,"stars":27,"repoUrl":28,"updatedAt":1344},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1468,1469,1470,1471,1472],{"name":1336,"slug":1337,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":1341,"slug":1342,"type":16},{"name":1274,"slug":1275,"type":16},{"slug":1346,"name":1346,"fn":1347,"description":1348,"org":1474,"tags":1475,"stars":27,"repoUrl":28,"updatedAt":1359},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1476,1477,1478,1479],{"name":1352,"slug":1353,"type":16},{"name":9,"slug":8,"type":16},{"name":1356,"slug":1357,"type":16},{"name":1274,"slug":1275,"type":16}]