MCPcopy Index your code
hub / github.com/redis/rueidis

github.com/redis/rueidis @v1.0.76

repository ↗ · DeepWiki ↗ · release v1.0.76 ↗ · Ask this repo → · + Follow
15,509 symbols 47,266 edges 208 files 655 documented · 4% 4 cross-repo links updated 15d agov1.0.76 · 2026-06-20★ 2,96011 open issues
README

rueidis

Go Reference CircleCI Go Report Card codecov

A fast Golang Redis client that does auto pipelining and supports server-assisted client-side caching.

Features


Getting Started

package main

import (
  "context"
  "github.com/redis/rueidis"
)

func main() {
  client, err := rueidis.NewClient(rueidis.ClientOption{InitAddress: []string{"127.0.0.1:6379"}})
  if err != nil {
    panic(err)
  }
  defer client.Close()

  ctx := context.Background()
  // SET key val NX
  err = client.Do(ctx, client.B().Set().Key("key").Value("val").Nx().Build()).Error()
  // HGETALL hm
  hm, err := client.Do(ctx, client.B().Hgetall().Key("hm").Build()).AsStrMap()
}

Check out more examples: Command Response Cheatsheet

Developer Friendly Command Builder

client.B() is the builder entry point to construct a redis command:

Developer friendly command builder\ Recorded by @FZambia Improving Centrifugo Redis Engine throughput and allocation efficiency with Rueidis Go library

Once a command is built, use either client.Do() or client.DoMulti() to send it to redis.

You ❗️SHOULD NOT❗️ reuse the command to another client.Do() or client.DoMulti() call because it has been recycled to the underlying sync.Pool by default.

To reuse a command, use Pin() after Build() and it will prevent the command from being recycled.

Pipelining

Auto Pipelining

All concurrent non-blocking redis commands (such as GET, SET) are automatically pipelined by default, which reduces the overall round trips and system calls and gets higher throughput. You can easily get the benefit of pipelining technique by just calling client.Do() from multiple goroutines concurrently. For example:

func BenchmarkPipelining(b *testing.B, client rueidis.Client) {
  // the below client.Do() operations will be issued from
  // multiple goroutines and thus will be pipelined automatically.
  b.RunParallel(func(pb *testing.PB) {
    for pb.Next() {
      client.Do(context.Background(), client.B().Get().Key("k").Build()).ToString()
    }
  })
}

Benchmark Comparison with go-redis v9

Compared to go-redis, Rueidis has higher throughput across 1, 8, and 64 parallelism settings.

It is even able to achieve ~14x throughput over go-redis in a local benchmark of MacBook Pro 16" M1 Pro 2021. (see parallelism(64)-key(16)-value(64)-10)

client_test_set

Benchmark source code: https://github.com/rueian/rueidis-benchmark

A benchmark result performed on two GCP n2-highcpu-2 machines also shows that rueidis can achieve higher throughput with lower latencies: https://github.com/redis/rueidis/pull/93

Disable Auto Pipelining

While auto pipelining maximizes throughput, it relies on additional goroutines to process requests and responses and may add some latencies due to goroutine scheduling and head of line blocking.

You can avoid this by setting DisableAutoPipelining to true, then it will switch to connection pooling approach and serve each request with dedicated connection on the same goroutine.

When DisableAutoPipelining is set to true, you can still send commands for auto pipelining with ToPipe():

cmd := client.B().Get().Key("key").Build().ToPipe()
client.Do(ctx, cmd)

This allows you to use connection pooling approach by default but opt-in auto pipelining for a subset of requests.

Manual Pipelining

Besides auto pipelining, you can also pipeline commands manually with DoMulti():

cmds := make(rueidis.Commands, 0, 10)
for i := 0; i < 10; i++ {
    cmds = append(cmds, client.B().Set().Key("key").Value("value").Build())
}
for _, resp := range client.DoMulti(ctx, cmds...) {
    if err := resp.Error(); err != nil {
        panic(err)
    }
}

When using DoMulti() to send multiple commands, the original commands are recycled after execution by default. If you need to reference them afterward (e.g. to retrieve the key), use the Pin() method to prevent recycling.

// Create pinned commands to preserve them from being recycled
cmds := make(rueidis.Commands, 0, 10)
for i := 0; i < 10; i++ {
  cmds = append(cmds, client.B().Get().Key(strconv.Itoa(i)).Build().Pin())
}

// Execute commands and process responses
for i, resp := range client.DoMulti(context.Background(), cmds...) {
  fmt.Println(resp.ToString()) // this is the result
  fmt.Println(cmds[i].Commands()[1]) // this is the corresponding key
}

Alternatively, you can use the MGet and MGetCache helper functions to easily map keys to their corresponding responses.

val, err := MGet(client, ctx, []string{"k1", "k2"})
fmt.Println(val["k1"].ToString()) // this is the k1 value

Server-Assisted Client-Side Caching

The opt-in mode of server-assisted client-side caching is enabled by default and can be used by calling DoCache() or DoMultiCache() with client-side TTLs specified.

client.DoCache(ctx, client.B().Hmget().Key("mk").Field("1", "2").Cache(), time.Minute).ToArray()
client.DoMultiCache(ctx,
    rueidis.CT(client.B().Get().Key("k1").Cache(), 1*time.Minute),
    rueidis.CT(client.B().Get().Key("k2").Cache(), 2*time.Minute))

Cached responses, including Redis Nils, will be invalidated either when being notified by redis servers or when their client-side TTLs are reached. See https://github.com/redis/rueidis/issues/534 for more details.

Benchmark

Server-assisted client-side caching can dramatically boost latencies and throughput just like having a redis replica right inside your application. For example:

client_test_get

Benchmark source code: https://github.com/rueian/rueidis-benchmark

Client-Side Caching Helpers

Use CacheTTL() to check the remaining client-side TTL in seconds:

client.DoCache(ctx, client.B().Get().Key("k1").Cache(), time.Minute).CacheTTL() == 60

Use IsCacheHit() to verify if the response came from the client-side memory:

client.DoCache(ctx, client.B().Get().Key("k1").Cache(), time.Minute).IsCacheHit() == true

If the OpenTelemetry is enabled by the rueidisotel.NewClient(option), then there are also two metrics instrumented:

  • rueidis_do_cache_miss
  • rueidis_do_cache_hits

MGET/JSON.MGET Client-Side Caching Helpers

rueidis.MGetCache and rueidis.JsonMGetCache are handy helpers fetching multiple keys across different slots through the client-side caching. They will first group keys by slot to build MGET or JSON.MGET commands respectively and then send requests with only cache missed keys to redis nodes.

Broadcast Mode Client-Side Caching

Although the default is opt-in mode, you can use broadcast mode by specifying your prefixes in ClientOption.ClientTrackingOptions:

client, err := rueidis.NewClient(rueidis.ClientOption{
  InitAddress:           []string{"127.0.0.1:6379"},
  ClientTrackingOptions: []string{"PREFIX", "prefix1:", "PREFIX", "prefix2:", "BCAST"},
})
if err != nil {
  panic(err)
}
client.DoCache(ctx, client.B().Get().Key("prefix1:1").Cache(), time.Minute).IsCacheHit() == false
client.DoCache(ctx, client.B().Get().Key("prefix1:1").Cache(), time.Minute).IsCacheHit() == true

Please make sure that commands passed to DoCache() and DoMultiCache() are covered by your prefixes. Otherwise, their client-side cache will not be invalidated by redis.

Client-Side Caching with Cache Aside Pattern

Cache-Aside is a widely used caching strategy. rueidisaside can help you cache data into your client-side cache backed by Redis. For example:

client, err := rueidisaside.NewClient(rueidisaside.ClientOption{
    ClientOption: rueidis.ClientOption{InitAddress: []string{"127.0.0.1:6379"}},
})
if err != nil {
    panic(err)
}
val, err := client.Get(context.Background(), time.Minute, "mykey", func(ctx context.Context, key string) (val string, err error) {
    if err = db.QueryRowContext(ctx, "SELECT val FROM mytab WHERE id = ?", key).Scan(&val); err == sql.ErrNoRows {
        val = "_nil_" // cache nil to avoid penetration.
        err = nil     // clear err in case of sql.ErrNoRows.
    }
    return
})
// ...

Please refer to the full example at rueidisaside.

Disable Client-Side Caching

Some Redis providers don't support client-side caching, ex. Google Cloud Memorystore. You can disable client-side caching by setting ClientOption.DisableCache to true. This will also fall back client.DoCache() and client.DoMultiCache() to client.Do() and client.DoMulti().

Context Cancellation

client.Do(), client.DoMulti(), client.DoCache(), and client.DoMultiCache() can return early if the context deadline is reached.

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
client.Do(ctx, client.B().Set().Key("key").Value("val").Nx().Build()).Error() == context.DeadlineExceeded

Please note that though operations can return early, the command is likely sent already.

Canceling a Context Before Its Deadline

Manually canceling a context is only work in pipeline mode, as it requires an additional goroutine to monitor the context. Pipeline mode will be started automatically when there are concurrent requests on the same connection, but you can start it in advance with ClientOption.AlwaysPipelining to make sure manually cancellation is respected, especially for blocking requests which are sent with a dedicated connection where pipeline mode isn't started.

Disable Auto Retry

All read-only commands are automatically retried on failures by default before their context deadlines exceeded. You can disable this by setting DisableRetry or adjust the number of retries and durations between retries using RetryDelay function.

Retryable Commands

Write commands can set Retryable to automatically retried on failures like read-only commands. Make sure you only use this feature with idempotent operations.

client.Do(ctx, client.B().Set().Key("key").Value("val").Build().ToRetryable())
client.DoMulti(ctx, client.B().Set().Key("key").Value("val").Build().ToRetryable())

Pub/Sub

To receive messages from channels, client.Receive() should be used. It supports SUBSCRIBE, PSUBSCRIBE, and Redis 7.0's SSUBSCRIBE:

err = client.Receive(context.Background(), client.B().Subscribe().Channel("ch1", "ch2").Build(), func(msg rueidis.PubSubMessage) {
    // Handle the message. If you need to perform heavy processing or issue
    // additional commands, do that in a separate goroutine to avoid
    // blocking the pipeline, e.g.:
    //   go func() {
    //       // long work or client.Do(...)
    //   }()
})

The provided handler will be called with the received message.

It is important to note that client.Receive() will keep blocking until returning a value in the following cases:

  1. return nil when receiving any unsubscribe/punsubscribe message related to the provided subscribe command, including sunsubscribe messages caused by slot migrations.
  2. return rueidis.ErrClosing when the client is closed manually.
  3. return ctx.Err() when the ctx is done.
  4. return non-nil err when the provided subscribe command fails.

While the client.Receive() call is blocking, the Client is still able to accept other concurrent requests, and they are sharing the same TCP connection. If your message handler may take some time to complete, it is recommended to use the client.Receive() inside a client.Dedicated() for not blocking other concurrent requests.

Subscription confirmations

Use rueidis.WithOnSubscriptionHook when you need to observe subscribe / unsubscribe confirmations that the server sends during the lifetime of a client.Receive().

The hook can be triggered multiple times because the client.Receive() may automatical

Extension points exported contracts — how you extend this code

Client (Interface)
Client is the redis client interface for both single redis instance and redis cluster. It should be created from the New [11 …
rueidis.go
Hook (Interface)
Hook allows user to intercept rueidis.Client by using WithHook [15 implementers]
rueidishook/hook.go
Container (Interface)
(no doc) [15 implementers]
internal/util/pool.go
Cmder (Interface)
(no doc) [8 implementers]
rueidiscompat/command.go
CacheEntry (Interface)
CacheEntry should be used to wait for a single-flight response when cache missed. [3 implementers]
cache.go
TypedCacheAsideClient (Interface)
TypedCacheAsideClient is an interface that provides a typed cache-aside client. It allows you to cache and retrieve valu [3 …
rueidisaside/typed_aside.go
BloomFilter (Interface)
BloomFilter based on Redis Bitmaps. BloomFilter uses a 128-bit murmur3 hash function. [2 implementers]
rueidisprob/bloomfilter.go
Scanner (Interface)
Scanner is the interface implemented by themselves, which will override the decoding behavior of decoderFunc. [2 implementers]
rueidiscompat/hscan.go

Core symbols most depended-on inside this repo

Build
called by 6936
internal/cmds/gen_set.go
Key
called by 4311
internal/cmds/gen_set.go
To
called by 2385
internal/cmds/gen_server.go
strmsg
called by 2185
message.go
Field
called by 2184
internal/cmds/gen_hash.go
As
called by 2137
internal/cmds/gen_search.go
Filter
called by 1974
internal/cmds/gen_vector_set.go
Property
called by 1840
internal/cmds/gen_search.go

Shape

Method 11,142
TypeAlias 2,575
Function 1,317
Struct 420
Interface 34
FuncType 21

Languages

Go100%

Modules by API surface

internal/cmds/gen_connection.go1,677 symbols
internal/cmds/gen_search.go1,649 symbols
rueidiscompat/adapter.go1,155 symbols
internal/cmds/gen_timeseries.go1,075 symbols
internal/cmds/gen_geo.go726 symbols
internal/cmds/gen_sorted_set.go559 symbols
rueidiscompat/pipeline.go536 symbols
internal/cmds/gen_stream.go479 symbols
internal/cmds/gen_string.go476 symbols
rueidiscompat/command.go461 symbols
internal/cmds/gen_server.go460 symbols
internal/cmds/gen_generic.go397 symbols

Dependencies from manifests, versioned

github.com/Masterminds/semver/v3v3.4.0 · 1×
github.com/cespare/xxhash/v2v2.3.0 · 1×
github.com/go-logr/logrv1.4.3 · 1×
github.com/go-logr/stdrv1.2.2 · 1×
github.com/go-task/slim-sprig/v3v3.0.0 · 1×
github.com/google/pprofv0.0.0-2026040205171 · 1×

For agents

$ claude mcp add rueidis \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact