Redis
Nimbus ships a thin redis package that wraps go-redis/v9, giving you a fully idiomatic Go Redis client. The same client is used internally by the queue, cache, session, Transmit, and Horizon plugins, so the dependency is already in your project.
Creating a client
Use redis.NewClient with an *redis.Options struct. The most common fields are Addr, Password, and DB.
import "github.com/CodeSyncr/nimbus/redis"
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // or os.Getenv("REDIS_URL")
Password: "", // no password by default
DB: 0, // default DB
})
If you prefer a URL (e.g. from .env), use redis.ParseURL:
opt, err := redis.ParseURL("redis://localhost:6379/0")
if err != nil {
log.Fatal(err)
}
rdb := redis.NewClient(opt)
Wiring into the container
Register the client as a singleton so controllers and services can resolve it from the IoC container:
func Boot() *nimbus.App {
config.Load()
app := nimbus.New()
// Redis singleton
rdb := redis.NewClient(&redis.Options{Addr: os.Getenv("REDIS_ADDR")})
app.Container.Singleton("redis", func() *redis.Client { return rdb })
start.RegisterMiddleware(app)
start.RegisterRoutes(app)
return app
}
Resolve it inside a controller or service:
type CacheController struct {
Redis *redis.Client
}
// In routes.go:
rdb := app.Container.MustMake("redis").(*redis.Client)
app.Router.Resource("cache", &controllers.CacheController{Redis: rdb})
Basic operations
Every Redis command is available directly on the client. All operations are async and accept a context.Context.
import (
"context"
"time"
"github.com/CodeSyncr/nimbus/redis"
)
ctx := context.Background()
// โโ Strings โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
err := rdb.Set(ctx, "username", "virk", 0).Err()
username, err := rdb.Get(ctx, "username").Result()
// With TTL
rdb.Set(ctx, "otp:12345", "982344", 5*time.Minute)
val, err := rdb.Get(ctx, "otp:12345").Result()
if err == redis.Nil {
// key does not exist or has expired
}
// โโ Increment / Decrement โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
rdb.Incr(ctx, "page_views")
rdb.IncrBy(ctx, "score", 10)
// โโ Expiry โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
rdb.Expire(ctx, "username", 30*time.Minute)
ttl, _ := rdb.TTL(ctx, "username").Result()
// โโ Existence check โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
exists, _ := rdb.Exists(ctx, "username").Result() // 1 = exists, 0 = not
rdb.Del(ctx, "username")
Hashes
// Set multiple fields
rdb.HSet(ctx, "user:1", "name", "Virk", "email", "virk@example.com")
// Get one field
name, _ := rdb.HGet(ctx, "user:1", "name").Result()
// Get all fields as map
fields, _ := rdb.HGetAll(ctx, "user:1").Result() // map[string]string
// Delete a field
rdb.HDel(ctx, "user:1", "email")
Lists
// Push to list
rdb.LPush(ctx, "notifications", "msg1", "msg2")
rdb.RPush(ctx, "queue", "job1")
// Pop from list
val, _ := rdb.LPop(ctx, "notifications").Result()
// Get range
items, _ := rdb.LRange(ctx, "notifications", 0, -1).Result()
Sets & Sorted Sets
// Sets
rdb.SAdd(ctx, "tags", "go", "nimbus", "redis")
members, _ := rdb.SMembers(ctx, "tags").Result()
isMember, _ := rdb.SIsMember(ctx, "tags", "go").Result()
// Sorted sets (leaderboard)
rdb.ZAdd(ctx, "leaderboard",
redis.Z{Score: 100, Member: "alice"},
redis.Z{Score: 85, Member: "bob"},
)
top, _ := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 9).Result()
Pub/Sub
// Subscribe
pubsub := rdb.Subscribe(ctx, "notifications")
defer pubsub.Close()
go func() {
for msg := range pubsub.Channel() {
fmt.Println("Received:", msg.Payload)
}
}()
// Publish from another goroutine or handler
rdb.Publish(ctx, "notifications", "new_order:42")
Error handling
Use redis.Nil to detect missing keys, and always check .Err() for write operations:
val, err := rdb.Get(ctx, "key").Result()
switch {
case err == redis.Nil:
// key does not exist
case err != nil:
// real Redis error (connection refused, timeout, etc.)
default:
fmt.Println("Value:", val)
}
// Write errors
if err := rdb.Set(ctx, "key", "value", 0).Err(); err != nil {
// handle error
}
Environment variable convention
Add to your .env:
REDIS_URL=redis://localhost:6379
# For password-protected Redis:
# REDIS_URL=redis://:password@localhost:6379/0
Then in Boot():
opt, _ := redis.ParseURL(os.Getenv("REDIS_URL"))
rdb := redis.NewClient(opt)
When to use Redis vs Cache
| Use case | Recommendation |
|---|---|
| Application caching (remember, tags) | cache package with Redis backend |
| Job queues, leaderboards, pub/sub | Direct redis.Client |
| Session persistence across restarts | Redis-backed session store |
| Rate limiting, presence, locks | Direct redis.Client or ratelimit_redis middleware |