encore-go-cache — Claude Code skill: Redis caching in Encore Go
A skill that shows the agent how to cache in Redis from Encore Go services: typed keyspaces, TTLs, atomic counters.
npx skills add encoredev/skills --skill encore-go-cache -a claude-code
npx skills add encoredev/skills --skill go-cache -a claude-codeWhat encore-go-cache does
The skill covers declaring a cache.Cluster in Encore Go and creating a keyspace per data shape. Keys are built from KeyPattern plus a key struct, and values stay typed: strings, ints, float64, JSON structs, lists and sets. Counters get atomic Increment and Decrement, conditional writes use SetIfNotExists and Replace.
Expiry comes from cache.ExpireIn, cache.ExpireDailyAt and cache.NeverExpire, while cache.KeepTTL leaves the current TTL alone on update. A miss surfaces as cache.Miss, a conflicting insert as cache.KeyExists, both checked with errors.Is. Eviction policy is set in ClusterConfig, and cache.AllKeysLRU is the default.
Local development runs an in-memory Redis capped at roughly 100 keys, so it is not the place for load tests. For durable storage the skill points you to encore-go-database on Postgres or encore-go-bucket for objects.
What it helps with
- cache a hot read in an Encore Go service
- rate-limit a user by counter
- store short-lived session tokens that expire
- build a leaderboard on atomic increments
- split cache access into keyspaces instead of hand-built string keys
Example prompts for the agent
- cache the user profile in Redis with encore-go-cache and a one-hour TTL
- add a per-user request counter with atomic Increment and a 10-second window
- store the session token in a keyspace with expiry and handle cache.Miss
How to install encore-go-cache
1Skills CLI (Vercel)
npx skills add encoredev/skills --skill encore-go-cache -a claude-codenpx skills add encoredev/skills --skill go-cache -a claude-code2Manually: put the files in place
~/.claude/skills/go-cache/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/go-cache/
1Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-cache -a codex2Manually: put the files in place
.agents/skills/go-cache/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-cache -a cursor2Manually: put the files in place
.cursor/skills/go-cache/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install encoredev/skills go-cache2Manually: put the files in place
.github/skills/go-cache/SKILL.md1Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-cache -a gemini-cli2Platform CLI
gemini skills install https://github.com/encoredev/skills --path encore/go-cacheManually: put the files in place
.devin/skills/go-cache/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-cache -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about encore-go-cache
How do I install encore-go-cache in Claude?
Run npx skills add encoredev/skills --skill encore-go-cache -a claude-code. The skill file lands at ~/.claude/skills/go-cache/SKILL.md.
What does encore-go-cache do?
It tells the agent how to work with caching in Encore Go: declare a cluster, create typed keyspaces, set TTLs and call atomic operations.
How is the cache different from the database and bucket in Encore?
The cache suits ephemeral data that expires. For durable storage the skill recommends encore-go-database on Postgres or encore-go-bucket for objects.
Source text
SKILL.md · Apache-2.0
---
name: encore-go-cache
description: Cache data in Redis from Encore Go using `cache.NewCluster` and typed keyspaces from `encore.dev/storage/cache`. Type-safe key/value access with TTLs, atomic increments, and per-keyspace data shapes.
when_to_use: >-
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/set keyspaces, TTL helpers (`cache.ExpireIn`, `cache.ExpireDailyAt`, `cache.NeverExpire`), atomic `Increment`/`Decrement`, `SetIfNotExists`, `Replace`, eviction policies, and `cache.Miss`/`cache.KeyExists` errors. Trigger phrases: "cache this", "Redis", "key-value store", "rate limit", "TTL", "expire after", "in-memory store", "session token store", "leaderboard counter".
---
# Encore Go Caching (Redis)
## Instructions
Encore 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.
### Cluster
```go
package mycache
import "encore.dev/storage/cache"
var Cluster = cache.NewCluster("my-cache", cache.ClusterConfig{
EvictionPolicy: cache.AllKeysLRU,
})
```
Eviction policies: `cache.AllKeysLRU` (default), `cache.NoEviction`, `cache.AllKeysLFU`, `cache.AllKeysRandom`, `cache.VolatileLRU`, `cache.VolatileLFU`, `cache.VolatileTTL`, `cache.VolatileRandom`.
### Keyspace types
Each keyspace has a key shape (used to build the Redis key from `KeyPattern`) and a value type.
```go
package mycache
import (
"context"
"time"
"encore.dev/storage/cache"
)
type TokenKey struct {
TokenID string
}
// Strings
var Tokens = cache.NewStringKeyspace[TokenKey](Cluster, cache.KeyspaceConfig{
KeyPattern: "token/:TokenID",
DefaultExpiry: cache.ExpireIn(time.Hour),
})
func example(ctx context.Context) {
_ = Tokens.Set(ctx, TokenKey{TokenID: "abc"}, "value")
val, err := Tokens.Get(ctx, TokenKey{TokenID: "abc"}) // cache.Miss on miss
_ = Tokens.Delete(ctx, TokenKey{TokenID: "abc"})
_ = val
_ = err
}
```
```go
// Integers (atomic counters)
type CounterKey struct {
UserID string
}
var Counters = cache.NewIntKeyspace[CounterKey](Cluster, cache.KeyspaceConfig{
KeyPattern: "requests/:UserID",
DefaultExpiry: cache.ExpireIn(10 * time.Second),
})
func incr(ctx context.Context) {
count, _ := Counters.Increment(ctx, CounterKey{UserID: "user123"}, 1)
_, _ = Counters.Decrement(ctx, CounterKey{UserID: "user123"}, 1)
_ = count
}
```
```go
// Structs (JSON-encoded)
type ProfileKey struct {
UserID string
}
type UserProfile struct {
Name string
Email string
}
var Profiles = cache.NewStructKeyspace[ProfileKey, UserProfile](Cluster, cache.KeyspaceConfig{
KeyPattern: "profile/:UserID",
DefaultExpiry: cache.ExpireIn(time.Hour),
})
func setProfile(ctx context.Context) {
_ = Profiles.Set(ctx, ProfileKey{UserID: "123"}, UserProfile{
Name: "Alice", Email: "[email protected]",
})
}
```
### Other keyspace types
All from `encore.dev/storage/cache`:
- `NewFloatKeyspace` — float64 values, has `Increment`.
- `NewListKeyspace` — list values, with `PushLeft`/`PushRight`/`PopLeft`/`PopRight`/`GetRange`.
- `NewSetKeyspace` — set values, with `Add`/`Remove`/`Contains`/`Items`.
### Multi-field key patterns
```go
type ResourceKey struct {
UserID string
ResourcePath string
}
var ResourceRequests = cache.NewIntKeyspace[ResourceKey](Cluster, cache.KeyspaceConfig{
KeyPattern: "requests/:UserID/:ResourcePath",
DefaultExpiry: cache.ExpireIn(10 * time.Second),
})
```
### Expiry helpers
```go
import (
"encore.dev/storage/cache"
"time"
)
cache.ExpireIn(time.Hour) // relative
cache.ExpireDailyAt(2, 0, 0, time.UTC) // specific UTC time each day
cache.NeverExpire // no expiry
cache.KeepTTL // keep existing TTL when updating
```
### Errors
```go
import "encore.dev/storage/cache"
val, err := keyspace.Get(ctx, key)
if errors.Is(err, cache.Miss) {
// not in cache
}
err = keyspace.SetIfNotExists(ctx, key, value)
if errors.Is(err, cache.KeyExists) {
// already there
}
```
## Guidelines
- Declare `cache.Cluster` and keyspaces as package-level variables.
- Pick the most specific keyspace type — `IntKeyspace` for counters gives you atomic `Increment`/`Decrement` for free.
- `Get()` returns `cache.Miss` on miss; `Replace()` and `SetIfNotExists()` return `cache.Miss`/`cache.KeyExists` on conflict.
- Local development uses an in-memory Redis with a ~100-key cap — don't load-test it.
- For durable storage, use `encore-go-database` (Postgres) or `encore-go-bucket` (object storage) instead.
© encoredev · Apache-2.0 · encoredev/skills