Valkey General Language Independent Driver for the Enterprise (GLIDE) is the official open-source Valkey client library, proudly part of the Valkey organization. The Ruby gem (valkey-rb) wraps Valkey GLIDE Core (Rust) and aims to be a drop-in replacement for redis-rb while delivering GLIDE performance, reliability, and enterprise features.
- Community and Open Source: Join our vibrant community and contribute to the project.
- Reliability: Built with best practices learned from over a decade of operating Redis OSS-compatible services.
- Performance: Optimized for high performance and low latency via the Rust-based GLIDE core.
- High Availability: Cluster-aware routing, reconnection, and fault tolerance.
- Cross-Language Consistency: Same core driver as Python, Java, Node.js, and Go clients.
- Drop-in Replacement: Familiar redis-rb-style API (
Valkey.new, command methods,pipelined, URL parsing). - Observability: Native OpenTelemetry tracing and client statistics.
- Command coverage: Implementation status wiki
- Valkey GLIDE overview: glide.valkey.io
- Supported engine versions: valkey-glide README — Supported Engine Versions
- Local development: DEVELOPER.md
| Engine Type | 6.2 | 7.0 | 7.1 | 7.2 | 8.0 | 8.1 | 9.0 |
|---|---|---|---|---|---|---|---|
| Valkey | - | - | - | ✓ | ✓ | ✓ | ✓ |
| Redis OSS | ✓ | ✓ | ✓ | ✓ | - | - | - |
The release of Valkey GLIDE Ruby was tested on the following platforms:
Linux:
- Ubuntu 20+ (x86_64/amd64 and arm64/aarch64)
- Amazon Linux 2 (AL2) and 2023 (AL2023) (x86_64)
- Alpine Linux 3.18+ (x86_64 and arm64/aarch64) — musl libc
macOS:
- macOS 14.7+ (Apple silicon / aarch64)
- macOS 13.7+ (x86_64 / amd64)
| Ruby Version | MRI | JRuby |
|---|---|---|
| 2.6 | ✓ | - |
| 2.7 | ✓ | - |
| 3.0 – 3.4 | ✓ | ✓ |
Minimum Ruby version: 2.6.0 (see valkey.gemspec).
Install from RubyGems:
gem install valkey-rbOr add to your Gemfile:
gem "valkey-rb"Verify installation:
ruby -e 'require "valkey"; puts Valkey::VERSION'The gem ships prebuilt native libraries (libglide_ffi.so on Linux, libglide_ffi.dylib on macOS) and depends on the ffi gem.
require "valkey"
client = Valkey.new(host: "localhost", port: 6379)
client.set("mykey", "hello world")
# => "OK"
client.get("mykey")
# => "hello world"
client.closeclient = Valkey.new(url: "redis://localhost:6379/0")
# TLS: rediss://user:password@localhost:6380/0
client.ping
# => "PONG"nodes = [
{ host: "127.0.0.1", port: 7000 },
{ host: "127.0.0.1", port: 7001 },
{ host: "127.0.0.1", port: 7002 },
{ host: "127.0.0.1", port: 7003 },
{ host: "127.0.0.1", port: 7004 },
{ host: "127.0.0.1", port: 7005 }
]
client = Valkey.new(nodes: nodes, cluster_mode: true)
client.set("foo", "bar")
client.get("foo")
# => "bar"Batch multiple commands in a single network round trip (non-atomic pipeline):
results = client.pipelined do |pipe|
pipe.set("key1", "value1")
pipe.get("key1")
pipe.incr("counter")
end
# => ["OK", "value1", 1]Note: Transactional commands (
MULTI/EXEC/DISCARD) in a pipeline are executed sequentially as a workaround for FFI batch stability. Prefermulti/execon the main client for transactions.
Not every command has a dedicated method yet. call/call_v are the escape hatch — send any
command as plain arguments and get the raw reply back, matching redis-client's #call/#call_v:
client.call("SET", "mykey", "value")
# => "OK"
client.call_v(["MGET"] + keys)call/call_v apply the same argument coercion as redis-client:
# Integers/Floats auto-stringify
client.call("SET", "mykey", 42)
# equivalent to call("SET", "mykey", "42")
# Arrays flatten (including nested arrays)
client.call("LPUSH", "list", [1, 2, 3])
# equivalent to call("LPUSH", "list", "1", "2", "3")
# Hashes flatten to alternating key/value
client.call("HMSET", "hash", { "foo" => "1" })
# equivalent to call("HMSET", "hash", "foo", "1")
# Keyword args become trailing command flags (call only, not call_v):
# a truthy value emits the upcased flag name; a non-boolean value also emits
# the stringified value. Falsy/nil values are dropped entirely, not stringified.
client.call("SET", "k", "v", nx: true, ex: 60)
# equivalent to call("SET", "k", "v", "NX", "EX", "60")
client.call("SET", "k", "v", nx: false, ex: nil)
# equivalent to call("SET", "k", "v")call_v takes the whole command as a single Array (no keyword flags) — useful when the command is
built dynamically. Both return the raw reply with no type-casting based on the command name.
| Option | Description |
|---|---|
host, port |
Server address (default 127.0.0.1:6379) |
url |
redis:// or rediss:// URI (merged with explicit options) |
db |
Database index (standalone only) |
password, username |
Authentication |
timeout |
Request timeout in seconds (default 5.0) |
connect_timeout |
Connection timeout in seconds |
ssl, ssl_params |
TLS (ca_file, cert, key, ca_path, root_certs) |
cluster_mode |
Enable cluster client |
nodes |
Array of { host:, port: } hashes |
protocol |
:resp2 (default) or :resp3 |
client_name |
CLIENT SETNAME value |
reconnect_attempts, reconnect_delay, reconnect_delay_max |
Connection retry strategy |
read_from (GLIDE-native) |
Read routing: :primary, :prefer_replica, :az_affinity, :az_affinity_replicas_and_primary symbols, the exact-match GLIDE strings (e.g. "PreferReplica"), or the Valkey::ReadFrom::* constants (e.g. Valkey::ReadFrom::PREFER_REPLICA). :az_affinity/:az_affinity_replicas_and_primary require client_az to also be set. LowestLatency is a valid GLIDE value but not yet usable via the vendored native library. |
client_az (GLIDE-native) |
Availability-zone identifier for :az_affinity / :az_affinity_replicas_and_primary routing (e.g. "us-west-2a") |
inflight_requests_limit (GLIDE-native) |
Maximum concurrent in-flight requests (non-negative integer) |
lazy_connect (GLIDE-native) |
Delay the actual connection until the first command is sent |
periodic_checks (GLIDE-native) |
Cluster topology health checks: { manual_interval: { duration_in_sec: N } } or { disabled: true }. Accepted (as a no-op) on standalone connections. |
client = Valkey.new(
host: "localhost",
port: 6379,
timeout: 2.0,
connect_timeout: 1.0,
client_name: "my-app",
protocol: :resp3
)Valkey GLIDE Ruby configures OpenTelemetry in the native Rust core (not via the Ruby opentelemetry-sdk gem). Initialize once per process before creating clients:
require "valkey"
Valkey::OpenTelemetry.init(
traces: {
endpoint: "http://localhost:4318/v1/traces",
sample_percentage: 10
},
metrics: {
endpoint: "http://localhost:4318/v1/metrics"
},
flush_interval_ms: 5000
)
client = Valkey.new(host: "localhost", port: 6379)
client.set("key", "value") # traced when sampling appliesSupported endpoint formats:
- HTTP/HTTPS:
http://localhost:4318/v1/traces - gRPC:
grpc://localhost:4317 - File (testing):
file:///tmp/valkey_traces.json
OpenTelemetry can only be initialized once per process. Spans are created in the FFI layer when sampling is enabled.
By default, every command span is an independent root span — it doesn't nest under your
application's request trace. To fix that, register a parent_span_context_provider: a
callable invoked before every command that returns the current W3C trace context (or nil
when there isn't one). When it returns a valid context, the command/pipeline span is created
as a child of it instead of an independent span.
require "valkey"
require "opentelemetry/sdk" # if your app uses the real opentelemetry-ruby gem
Valkey::OpenTelemetry.init(
traces: { endpoint: "http://localhost:4318/v1/traces", sample_percentage: 10 }
)
Valkey::OpenTelemetry.set_parent_span_context_provider do
span = ::OpenTelemetry::Trace.current_span
next nil unless span.context.valid?
{
trace_id: span.context.hex_trace_id,
span_id: span.context.hex_span_id,
trace_flags: span.context.trace_flags.sampled? ? 1 : 0,
tracestate: span.context.tracestate.to_s
}
endThe provider must return either nil or a Hash with :trace_id (32-char lowercase hex),
:span_id (16-char lowercase hex), :trace_flags (Integer 0-255), and :tracestate
(String or nil). Anything else is rejected with a warning and treated as nil — a broken
provider degrades to independent root spans, it never raises into your command path.
You can also pass parent_span_context_provider: directly to init(...) instead of calling
set_parent_span_context_provider separately.
Note on the OpenTelemetry constant name: Valkey::OpenTelemetry (this gem's module) and
the real opentelemetry-ruby gem's top-level ::OpenTelemetry module are unrelated constants
and don't collide. But if you write a provider block from code that's lexically nested inside
Valkey (uncommon for typical app-level code), a bare OpenTelemetry::Trace reference would
resolve to Valkey::OpenTelemetry::Trace (undefined) instead of the real gem — always use the
leading-:: form, ::OpenTelemetry::Trace, as in the example above.
Runnable examples are in examples/:
bundle exec ruby examples/standalone.rb
bundle exec ruby examples/pipelining.rb
bundle exec ruby examples/opentelemetry.rbSee examples/README.md for cluster setup and environment variables.
Monitor global client metrics (shared across all clients in the process):
stats = client.get_statistics
# alias: client.statistics
puts "Connections: #{stats[:total_connections]}"
puts "Clients: #{stats[:total_clients]}"
puts "Compressed values: #{stats[:total_values_compressed]}"Available keys: :total_connections, :total_clients, :total_values_compressed, :total_values_decompressed, :total_original_bytes, :total_bytes_compressed, :total_bytes_decompressed, :compression_skipped_count.
Pub/Sub uses a native callback registered at connection time. Configure subscriptions via command modules (subscribe, psubscribe, etc.). See DEVELOPER.md and integration tests in test/valkey/pubsub_commands_test.rb for details.
| Path | Purpose |
|---|---|
lib/valkey.rb |
Main client: connection, pipelining, response conversion |
lib/valkey/bindings.rb |
FFI bindings to libglide_ffi |
lib/valkey/commands/ |
Command modules (strings, hashes, streams, cluster, JSON, vector search, …) |
lib/valkey/opentelemetry.rb |
OpenTelemetry configuration |
lib/valkey/pipeline.rb |
Pipeline command batching |
test/valkey/ |
Standalone integration tests |
test/cluster/ |
Cluster integration tests |
test/lint/ |
Shared lint tests (redis-rb compatibility patterns) |
This client mirrors redis-rb conventions where possible:
Valkey.newwithurl,host,port,db,ssl_params- Command method names and argument ordering aligned with redis-rb
pipelined,multi/exec,disconnect!(alias ofclose)
Not every redis-rb API is implemented yet. See the command implementation wiki for coverage.
Instructions for building from source, updating the FFI library, running tests, and contributing are in DEVELOPER.md.
For AI-assisted development, see AGENTS.md and CLAUDE.md.
Contributing: CONTRIBUTING.md.
We encourage you to join our community to support, share feedback, and ask questions on Valkey Slack: Join Valkey Slack.
Report issues: valkey-glide-ruby issues.
Apache-2.0 — see LICENSE in the repository.