ss-keel-redis
ss-keel-redis is the official cache addon for Keel. It wraps go-redis v9 and implements the contracts.Cache interface defined in ss-keel-core.
Implements: contracts.Cache
Current stable release: v1.3.2 (2026-04-22)
Browse this addon
Section titled “Browse this addon”Installation
Section titled “Installation”keel add redisOr manually:
go get github.com/slice-soft/ss-keel-redisBootstrap
Section titled “Bootstrap”When you run keel add redis, the CLI creates cmd/setup_redis.go and adds one line to cmd/main.go:
// cmd/setup_redis.go — created by keel add redispackage main
import ( "github.com/slice-soft/ss-keel-core/config" "github.com/slice-soft/ss-keel-core/core" "github.com/slice-soft/ss-keel-core/logger" ssredis "github.com/slice-soft/ss-keel-redis/redis")
// setupRedis initialises the Redis connection and registers a health checker.func setupRedis(app *core.App, log *logger.Logger) *ssredis.Client { redisConfig := config.MustLoadConfig[ssredis.Config]() redisConfig.Logger = log
client, err := ssredis.New(redisConfig) if err != nil { log.Error("failed to initialize redis: %v", err) } app.RegisterHealthChecker(ssredis.NewHealthChecker(client)) return client}The following is injected into cmd/main.go:
redisClient := setupRedis(app, appLogger)defer redisClient.Close()Generated configuration
Section titled “Generated configuration”When you install ss-keel-redis with keel add redis, the CLI appends these generated keys:
| application.properties | .env | Default | Purpose |
|---|---|---|---|
redis.url | REDIS_URL | redis://localhost:6379 | Redis connection URL used by the generated setupRedis bootstrap. |
Generated snippet:
redis.url=${REDIS_URL:redis://localhost:6379}Configuration
Section titled “Configuration”client, err := ssredis.New(ssredis.Config{ URL: "redis://localhost:6379", // required SkipPing: false, // set true in tests Pool: ssredis.PoolConfig{ MaxActiveConns: 10, MinIdleConns: 2, MaxIdleConns: 5, ConnMaxIdleTime: 5 * time.Minute, ConnMaxLifetime: 30 * time.Minute, }, Logger: log, // optional — logs "redis connected [url=...]"})Useful defaults:
MaxActiveConns:10MinIdleConns:2MaxIdleConns:5ConnMaxIdleTime:5mConnMaxLifetime:30m
The URL field uses the standard Redis URL format: redis://[:password@]host[:port][/db-number].
Official example
Section titled “Official example”The official examples repository includes ss-keel-examples/examples/14-redis-cache, which demonstrates:
ssredis.New(...)andssredis.NewHealthChecker(...)- injecting
*ssredis.Clientinto a module - using
contracts.Cachein the service layer - a cache-aside flow with
GET /notes/:id, Redis TTL, and cache invalidation on writes
Cache operations
Section titled “Cache operations”contracts.Cache covers the four core operations:
import ( "context" "time")
ctx := context.Background()
// Store a value with a TTLerr := redisClient.Set(ctx, "user:123", []byte(`{"name":"Alice"}`), 5*time.Minute)
// Retrieve — returns nil, nil when the key does not existval, err := redisClient.Get(ctx, "user:123")
// Remove a keyerr = redisClient.Delete(ctx, "user:123")
// Check existence without reading the valueexists, err := redisClient.Exists(ctx, "user:123")A zero TTL in Set means no expiration.
Injecting the cache into a module
Section titled “Injecting the cache into a module”Pass *ssredis.Client to any service that declares contracts.Cache:
package users
import ( "github.com/slice-soft/ss-keel-core/contracts" "github.com/slice-soft/ss-keel-core/core" ssredis "github.com/slice-soft/ss-keel-redis/redis")
type UsersModule struct { cache *ssredis.Client}
func NewUsersModule(cache *ssredis.Client) *UsersModule { return &UsersModule{cache: cache}}
func (m *UsersModule) Register(app *core.App) { repo := NewUserRepository(app.Logger()) service := NewUserService(repo, m.cache) app.RegisterController(NewUserController(service))}In cmd/main.go, pass the client when registering the module:
redisClient := setupRedis(app, appLogger)defer redisClient.Close()
app.RegisterModule(users.NewUsersModule(redisClient))Advanced operations
Section titled “Advanced operations”When the generic contracts.Cache interface is not enough, use RDB() to access the full go-redis client:
pipe := redisClient.RDB().Pipeline()pipe.Incr(ctx, "counter")pipe.Expire(ctx, "counter", time.Hour)_, err := pipe.Exec(ctx)Health integration
Section titled “Health integration”NewHealthChecker(client) implements contracts.HealthChecker and exposes the dependency under GET /health as:
{ "redis": "UP" }setupRedis registers it automatically. If you initialise the client manually, register it explicitly:
app.RegisterHealthChecker(ssredis.NewHealthChecker(client))