mcpField
E
encore-go-cache

encore-go-cache

github.com/encoredevData & databases30314 installsUpdated 2d ago
Repository

About encore-go-cache

A skill guide for using Encore Go’s typed Redis cache, aimed at developers building Go services. It covers keyspaces, expiry, eviction policies, and cache operations.

Key features

  1. 01Typed Redis keyspaces
  2. 02Integer and float counters
  3. 03List and set operations
  4. 04Configurable expiry and eviction
  5. 05Cache miss and conflict handling

Use cases

  1. 01Caching structured Go values
  2. 02Tracking atomic request counters
  3. 03Storing lists or sets in Redis

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/encoredev/skills --skill encore-go-cache

After installing, type/encore-go-cachein Claude Code to confirm it loaded.

Details

From the project README

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
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.

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
}
// 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
}
// 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
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
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
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.

Comments

Markdown supported