rueidis is a free, open source databases project written in Go and released under Apache-2.0. It has 2,981 GitHub stars, 258 forks and 12 open issues, and was last pushed 2 days ago. On this registry it ranks #184 of 203 tracked projects in Databases, with 5 head-to-head comparisons available.

What is rueidis?

rueidis is an Apache-2.0 licensed Go client for Redis, built for Go developers and platform teams that need high-throughput, low-latency access to Redis, Redis Cluster, or Sentinel from concurrent application code.

What it is

rueidis is a Redis client library written in Go, published under the Apache-2.0 licence and developed in the github.com/redis/rueidis repository. It speaks RESP3 and is designed around two ideas: automatic pipelining of concurrent non-blocking commands, and server-assisted client-side caching. The project lives in the Go and Redis client ecosystem, and the README explicitly frames it as an alternative to go-redis, including a rueidiscompat package that provides a go-redis-like API adapter.

The concrete problem it replaces is the round-trip cost and allocation overhead of issuing Redis commands one connection at a time from many goroutines. With rueidis, every concurrent non-blocking command sent through client.Do() is pipelined automatically, which reduces network round trips and system calls without the caller writing batching logic. It also replaces the pattern of hand-rolling cache invalidation: client-side caching is assisted by the server over RESP3, so locally cached entries are invalidated when the underlying keys change.

Key capabilities

  • Auto pipelining: concurrent non-blocking commands such as GET and SET issued via client.Do() from multiple goroutines are pipelined by default, with no explicit batch call required.
  • Server-assisted client-side caching over RESP3, which is the feature the project is best known for.
  • Command builder accessed through client.B(), with client.Do() and client.DoMulti() for dispatch; commands are recycled through a sync.Pool unless Pin() is called after Build().
  • Distributed locks in the rueidislock package, built on top of client-side caching.
  • Cache-Aside helper in rueidisaside and generic object mapping in the om package.
  • Protocol and data-structure coverage including Pub/Sub, Sharded Pub/Sub, Streams, Redis Cluster, Sentinel, RedisJSON, RedisBloom, RediSearch, and RedisTimeseries.
  • Probabilistic data structures via rueidisprob without requiring Redis Stack, plus availability zone affinity routing for cluster deployments.

Who uses it and how

  • High-concurrency Go services that need higher throughput from the same Redis deployment; the README reports roughly 14x throughput over go-redis on a local benchmark on a MacBook Pro 16-inch M1 Pro from 2021, measured at parallelism of 1, 8, and 64.
  • Real-time and messaging infrastructure: Centrifugo documented improving its Redis engine throughput and allocation efficiency by switching to rueidis.
  • Teams operating Redis Cluster or Sentinel that want cluster-aware routing and availability zone affinity rather than manual connection management.
  • Services that need distributed locking without adding a separate locking library, using rueidislock.
  • Teams that want OpenTelemetry traces (rueidisotel) and custom hooks (rueidishook) wired into their Redis calls.

Getting started

Install the module with go get github.com/redis/rueidis, then construct a client with rueidis.NewClient(rueidis.ClientOption{InitAddress: []string{"127.0.0.1:6379"}}). No hosted or managed option is described in the README; the package connects to a Redis endpoint the operator supplies.

How it compares

The only comparable tool named in the facts is go-redis, the dominant Go Redis client, and rueidis positions itself against it on throughput, reporting higher results across the benchmark parallelism settings the README publishes. It also ships a rueidiscompat adapter so code written against a go-redis-like API can migrate without a full rewrite. The distinguishing capability is that client-side caching and auto pipelining are defaults rather than opt-in additions.

When to use it — and when not to

A self-hoster must operate the Redis server (or cluster, or Sentinel setup) that rueidis connects to, because the library is a client and the README describes no hosting or managed offering. It is not the right choice for non-Go stacks, and its command recycling model is a real footgun: a command returned by Build() must not be reused in another client.Do() or client.DoMulti() call unless Pin() was called first. Teams without a RESP3-capable server also lose the client-side caching benefit that motivates choosing rueidis in the first place.

project readme (upstream, from github) — read inline

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 !

readme truncated — read the full docs on github

Frequently asked questions

Is rueidis free to use?

rueidis is open source under the Apache-2.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does rueidis do?

A fast Golang Redis client that supports Client Side Caching, Auto Pipelining, RDMA, etc.

What is rueidis written in?

rueidis is primarily written in Go. Its source is publicly available at https://github.com/redis/rueidis, and it has 2,981 GitHub stars.