Library / SDK
redis/redis-rb avatar
redis/redis-rb

One Redis instance means one connection, protected by a mutex

A Ruby client library for Redis

4,001 stars1,032 forksRubyMIT

At a glance

What is it?
redis-rb is the official Ruby client for Redis, and version 6.0 made RESP3 the default protocol, which removed a reshaping pass from the Ruby side and changed the return type of one geo command. The connection model is the other half of the story: there is no pool, and the documentation tells you to bring one.
Who is it for?
redis-rb suits a Ruby service that wants the Redis command surface without translation, and version 6.0 is the reason to look at it now, since the protocol change removes client side work rather than adding API to learn. Three things to check first.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • redis/redis-rb4,001 ★ · -3
Star history
Repository2026-09-242026-11-14
redis/redis-rb4k4k

-3 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

One instance means one connection, and you bring the pool

This is stated plainly and it shapes everything else about using the client: it does not provide connection pooling. Each `Redis` instance has one and only one connection to the server, and use of that connection is protected by a mutex.

The recommended arrangement wraps it in the connection_pool gem:

ruby
module MyApp
  def self.redis
    @redis ||= ConnectionPool::Wrapper.new do
      Redis.new(url: ENV["REDIS_URL"])
    end
  end
end

MyApp.redis.incr("some-counter")

The example tree shows the shape of the gap. There is a `keyspace_notifications.rb` example and, right beside it, `keyspace_notifications_pool.rb`, because keyspace notifications are the case where the single connection constraint bites: a subscription occupies the connection it was made on, so a second caller needs a second connection, which means a pool.

Other examples cover the same ground from different angles: `pubsub.rb`, `sentinel.rb` alongside a `sentinel/` directory, `dist_redis.rb`, `consistency.rb`, `incr-decr.rb`, `sets.rb`, `list.rb`, a `search/` directory and an `unicorn/` example for running under a preforking server.

RESP3 became the default, and one geo command changed its type

Starting in 6.0 the client negotiates RESP3 by sending `HELLO 3`, and you do not have to configure anything. Servers that cannot do it, meaning Redis older than 6.0 or anything that answers `NOPROTO`, are detected on connect and the client falls back to RESP2 transparently.

Return values are otherwise unchanged from 5.x, with one exception stated explicitly: `GEOPOS`, and `GEOSEARCH` or `GEORADIUS` with `WITHCOORD`, now return coordinates as a Float rather than a String.

That single line is the entire upgrade hazard, and it is a type change rather than a shape change, so code that interpolates the result into a string or compares it against one will not raise where it used to succeed. If you need the old behaviour for one call site or for a whole service, the opt out is a constructor argument:

ruby
redis = Redis.new(protocol: 2)

The migration guide is kept in the repository at `specs/migration-resp3.md`, so the details beyond the summary live with the code rather than only on a website.

What RESP3 removes is the Ruby side reshaping pass

The argument for RESP3 is structural rather than cosmetic. Under RESP2, structured replies arrive as flat arrays of bulk strings and the client converts them in Ruby before you see them: `HGETALL` turns a flat field, value, field, value array into a Hash, and sorted set scores are converted from String to Float pair by pair. Under RESP3 the server tags those replies as native maps and doubles, so the Hash and the Float come straight out of the parser and that pass disappears.

The project quantifies it with a script in the tree, `bench/resp_comparison.rb`, run on Ruby 3.4 with 100 element replies. Hash reads are reported as consistently using around ten to twenty five percent less client CPU per call on both drivers. With the hiredis driver, where parsing happens in C, sorted set reads with scores are reported as gaining up to sixteen percent throughput and about twenty percent less CPU per call on top of that; with the pure Ruby driver those sorted set reads are unchanged, because the parser there spends in Ruby roughly what the reshaping pass used to cost. Simple string commands and stream commands are unaffected either way.

Read as a summary: RESP3 is never slower where it matters, and it pairs best with the C driver, since that combination moves reply construction out of Ruby entirely.

CLIENT SETINFO names the client, and older servers reject it harmlessly

On connect the client tells the server what it is, so the library and its version show up in `CLIENT LIST` and `CLIENT INFO` as a lib-name and lib-ver pair. A gem built on top of redis-rb can add its own identity:

ruby
Redis.new(driver_info: "my-gem_v#{MyGem::VERSION}")
# reported as: lib-name=redis-rb(my-gem_v1.0.0) lib-ver=<Redis::VERSION>

The recommended suffix format follows the convention the official client libraries use: a name, the letter v, and a version, joined by underscore characters. Two details protect the wrapping gem. The suffix extends the reported name rather than replacing it, so redis-rb stays identifiable no matter what you pass, and an array of suffixes is accepted and joined with a semicolon.

There is also a sanitising step, because the server rejects some bytes: runs of characters it would refuse, spaces and non printable bytes, and the parentheses that delimit the suffix are each collapsed to one replacement character, or dropped at the edges of the value.

Compatibility is handled by ignoring the problem. Servers older than 7.2 do not support `CLIENT SETINFO`, they reject it, the error is discarded and the connection is used as normal. If something in front of the server, a proxy for instance, cannot tolerate the command at all, `driver_info: false` turns identification off.

A URL password with a special character has to be escaped first

Connection options can be given five ways, and one of them has a trap in it. The plain form assumes a default server on localhost port 6379. Host, port and database are named directly:

ruby
redis = Redis.new(host: "10.0.1.1", port: 6380, db: 15)

A `redis://` URL is also accepted, with the password in the userinfo part:

ruby
redis = Redis.new(url: "redis://:[email protected]:6380/15")

The trap is that the client expects passwords with special characters to be URL encoded, with `CGI.escape(password)` named as the way to do it. A password containing an at sign, a slash or a hash therefore fails in a way that looks like an authentication failure rather than a parsing one.

The remaining three forms are a Unix socket path, a password for a protected instance, and a username with a password for an ACL based one. Sentinel is separate again and needs Redis 2.8 or newer, plus a list of sentinel addresses and the name of the master to track.

Six Docker profiles on one amd64 only test image

The test infrastructure is a compose file that chooses a topology by profile: standalone for just the master, replica for master and replica without sentinels, sentinel for master, replica and three sentinels, cluster for a six node cluster, modules for a Redis Stack instance for the module tests, and all for everything at once.

Two constraints in that file shape local development. The image is `redislabs/client-libs-test` at a default version of 8.8.0, overridable with `REDIS_VERSION`, and it is amd64 only, so the platform is pinned and on Apple Silicon the containers run under Rosetta emulation. And the services use host networking, at the ports redis-rb has historically used, 6381, 6382, 6383, 6400 to 6402 and 16380 to 16385, because that is the simplest arrangement that keeps sentinel and cluster reporting host reachable addresses.

The macOS note is the part worth knowing before you start. Docker Desktop needs its host networking beta feature enabled, otherwise Linux containers can use host networking inside the VM but their ports do not appear on the macOS host, and the test run fails in a way that looks like a client bug. Continuous integration runs on Linux and is unaffected.

The standalone service also shows what the harness passes to Redis: a port from the environment, cluster mode off, protected mode off, an extra include file and a Unix socket at `/sockets/redis.sock` with permission 777.

Two task runners, a rubocop todo file, and both specs and test

The tree carries the tooling of a long lived library. There is a `Rakefile` and, beside it, a `makefile`, so two entry points for the same chores. Linting is RuboCop with two configuration files, a `.rubocop.yml` and a `.rubocop_todo.yml`, the second being the accumulated list of offences the project has chosen not to fix yet. `.ruby-version` pins the interpreter and `.yardopts` configures the generated documentation.

There are two test directories, `specs/` and `test/`, which is a leftover from a migration rather than a design decision, and `specs/` also holds the protocol migration guide. A `bench/` directory holds the RESP2 against RESP3 comparison script, and `bin/` and `cluster/` sit alongside `lib/`.

The repository also carries `AGENTS.md` and `CLAUDE.md` at the root, alongside the changelog, the gemspec, a Gemfile and a `.claude/` directory, so instructions for coding agents are versioned with the code.

What is not in the tree is a homepage: the project record carries none, and the API documentation is pointed at from RubyDoc rather than hosted here.

Ruby 3.2 and newer, with a single release tag at 6.0.0

The support statement is short on the language side and delegated on the server side. The client targets actively supported runtimes, which means Ruby 3.2 and newer, with a link to the Ruby maintenance branches page for each version's status and dates. On the server side it follows whatever versions Redis designates for support, again linked rather than restated.

So the client does not pin a server range of its own. What it does have is a compatibility mechanism: the RESP3 fallback on connect for anything that answers `NOPROTO`, and the tolerated rejection of `CLIENT SETINFO` on servers before 7.2.

The release history in the repository record lists one tag, v6.0.0, published on 2026-07-31, which is the release that made RESP3 the default. The default branch is `master` and it was last pushed on 2026-10-02, so the branch has moved about two months past that tag.

Installation is the one line you would expect, `gem install redis`, and the gem is MIT licensed with the command surface kept identical to the server's own names, so most of what you already know about Redis applies to the method names here.

Editorial conclusion

redis-rb suits a Ruby service that wants the Redis command surface without translation, and version 6.0 is the reason to look at it now, since the protocol change removes client side work rather than adding API to learn. Three things to check first. Decide whether RESP3's changed geo return type affects your code before upgrading, and pass protocol: 2 if it does. Bring your own pool, because a single instance holds a single connection behind a mutex and the concurrency ceiling follows from that. And if you wrap it, read the keyspace notification examples, since that is the case the project itself demonstrates with a pooling variant rather than with the plain client.

Frequently asked questions

Does redis-rb provide connection pooling?

No. Each Redis instance holds one and only one connection to the server and protects its use with a mutex, and the project recommends wrapping the client in the connection_pool gem.

What changed in redis-rb 6.0?

The client negotiates RESP3 by default with HELLO 3, falling back to RESP2 automatically on servers that reply NOPROTO. Command return values are otherwise unchanged, except GEOPOS and GEOSEARCH or GEORADIUS with WITHCOORD, which now return Float instead of String.

How do I keep redis-rb on RESP2?

Pass protocol: 2 to the constructor, for example Redis.new(protocol: 2). The client then keeps the previous behaviour without any other configuration.

How does a gem built on redis-rb report its own name?

With driver_info:, using a suffix in the <name>_v<version> form. The suffix extends the reported name rather than replacing it, so redis-rb stays identifiable, and an array of suffixes is accepted and joined with a semicolon.

Which Ruby and Redis versions does redis-rb support?

Ruby 3.2 and newer, and the server versions Redis designates for support. The client also identifies itself with CLIENT SETINFO, which servers older than 7.2 reject, and that rejection is ignored.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. redis/redis-rb on GitHub
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/redis-redis-rb.svg)](https://hysenlabs.com/projects/redis-redis-rb)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/redis-redis-rb.svg)](https://hysenlabs.com/projects/redis-redis-rb)

Was this useful?