Skip to content

go-redis

Databases & CachingCaching/Distributed DataGo

What it is

go-redis is the most widely used Redis client for Go, supporting cluster mode, sentinel, pipelining, pub/sub and streams with a context-aware API.

The client covers the full Redis command set with typed methods, plus connection pooling, automatic retries, pipelining and transactions.

Installation

go get github.com/redis/go-redis/v9

Getting started

The smallest useful thing you can do with it, and what each part means.

Get, set and expiry
rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    PoolSize: 20,
})
defer rdb.Close()

if err := rdb.Set(ctx, "book:42", payload, 10*time.Minute).Err(); err != nil {
    return err
}

val, err := rdb.Get(ctx, "book:42").Result()
if errors.Is(err, redis.Nil) {
    return ErrCacheMiss // redis.Nil means the key does not exist
}
redis.Nil is a sentinel, not a failure — treating it as an error is the most common mistake with this client. Always set an expiry unless you genuinely want the key to live forever.
Pipelining round trips
pipe := rdb.Pipeline()
incr := pipe.Incr(ctx, "views:42")
pipe.Expire(ctx, "views:42", time.Hour)
_, err := pipe.Exec(ctx)

fmt.Println(incr.Val()) // results are readable after Exec
Pipelining sends both commands in a single round trip. Over a network this is often a larger win than any server-side optimisation.

Advanced usage

Where the library earns its place over a simpler alternative.

Cache-aside with a typed helper
func cached[T any](ctx context.Context, rdb *redis.Client, key string,
    ttl time.Duration, load func() (T, error)) (T, error) {

    var zero T
    if data, err := rdb.Get(ctx, key).Bytes(); err == nil {
        var out T
        if json.Unmarshal(data, &out) == nil {
            return out, nil
        }
    } else if !errors.Is(err, redis.Nil) {
        return zero, err // a real Redis failure, not a miss
    }

    value, err := load()
    if err != nil { return zero, err }

    if data, err := json.Marshal(value); err == nil {
        rdb.Set(ctx, key, data, ttl) // best effort
    }
    return value, nil
}
Note the distinction between a cache miss and a Redis outage: a miss falls through to the loader, while a real error propagates. Cache writes are best-effort so a Redis problem degrades performance rather than breaking the request.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

redis: nil
The key does not exist. This is a normal cache miss — compare with errors.Is(err, redis.Nil) rather than treating it as a failure.
connection pool timeout
All pooled connections are busy. Raise PoolSize, lower the time each command holds a connection, or check for a slow command such as an unbounded KEYS.

Best practices

  • Always check errors.Is(err, redis.Nil) before treating a Get failure as an error.
  • Set an explicit TTL on cache keys; unbounded keys eventually fill memory.
  • Reuse one client — it pools connections internally; creating one per request defeats that.
  • Use pipelining or MGET to collapse multiple round trips.

Background

Why it exists, and what it was reacting to.

Maintained by Vladimir Mihailenco, go-redis became the community default for its complete command coverage and reliable cluster support. It is now published under the redis/go-redis path as an officially recognised client.