-
Notifications
You must be signed in to change notification settings - Fork 109
Migration Guide go‐redis
This guide provides a comprehensive comparison of how to migrate from go-redis to Valkey Glide, with side-by-side code examples to make the transition as smooth as possible.
go get github.com/valkey-io/valkey-glide/go/v2
go mod tidy
- go-redis offers multiple client types and configuration options for different connection scenarios
- Glide uses a single configuration object that comes pre-configured with best practices
Glide typically requires minimal configuration changes for:
- Timeout settings
- TLS configuration
- Read from replica settings
- User authentication (username & password)
For advanced configurations, refer to the Valkey Glide Wiki - Go.
Standalone Mode
go-redis
import (
"context"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
// Simple connection
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
// With options
rdbWithOptions := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Username: "user",
Password: "password",
})
Glide
import (
"context"
"github.com/valkey-io/valkey-glide/go/v2"
"github.com/valkey-io/valkey-glide/go/v2/config"
)
var ctx = context.Background()
// Simple connection
client, err := glide.NewClient(&config.ClientConfiguration{
Addresses: []config.NodeAddress{
{Host: "localhost", Port: 6379},
},
})
// With options
clientWithOptions, err := glide.NewClient(&config.ClientConfiguration{
Addresses: []config.NodeAddress{
{Host: "localhost", Port: 6379},
},
UseTLS: true,
Credentials: &config.ServerCredentials{
Username: "user",
Password: "password",
},
ReadFrom: config.ReadFromAZAffinity,
RequestTimeout: 2000 * time.Millisecond,
ConnectionBackoff: &config.ConnectionBackoffStrategy{
NumberOfRetries: 5,
Factor: 2,
ExponentBase: 2,
JitterPercent: 10,
},
AdvancedConfiguration: &config.AdvancedClientConfiguration{
ConnectionTimeout: 5000 * time.Millisecond,
TLSAdvancedConfiguration: &config.TLSAdvancedConfiguration{
UseInsecureTLS: false,
},
},
DatabaseId: 0,
})
Cluster Mode
go-redis
import (
"github.com/redis/go-redis/v9"
)
cluster := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379", "127.0.0.1:6380"},
})
// With options
clusterWithOptions := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379", "127.0.0.1:6380"},
Username: "user",
Password: "password",
})
Glide
import (
"github.com/valkey-io/valkey-glide/go/v2"
"github.com/valkey-io/valkey-glide/go/v2/config"
)
client, err := glide.NewClusterClient(&config.ClusterClientConfiguration{
Addresses: []config.NodeAddress{
{Host: "127.0.0.1", Port: 6379},
{Host: "127.0.0.1", Port: 6380},
},
})
// With options
clientWithOptions, err := glide.NewClusterClient(&config.ClusterClientConfiguration{
Addresses: []config.NodeAddress{
{Host: "127.0.0.1", Port: 6379},
{Host: "127.0.0.1", Port: 6380},
},
UseTLS: true,
Credentials: &config.ServerCredentials{
Username: "user",
Password: "password",
},
ReadFrom: config.ReadFromAZAffinity,
RequestTimeout: 2000 * time.Millisecond,
ConnectionBackoff: &config.ConnectionBackoffStrategy{
NumberOfRetries: 5,
Factor: 2,
ExponentBase: 2,
JitterPercent: 10,
},
AdvancedConfiguration: &config.AdvancedClusterClientConfiguration{
ConnectionTimeout: 5000 * time.Millisecond,
TLSAdvancedConfiguration: &config.TLSAdvancedConfiguration{
UseInsecureTLS: false,
},
},
})
Constructor Parameters Comparison
The table below compares go-redis options with Glide configuration parameters:
go-redis Parameter | Equivalent Glide Configuration |
---|---|
Addr: string |
Addresses: []config.NodeAddress{{Host: string, Port: int}} |
Username: string |
Credentials: &config.ServerCredentials{Username: string} |
Password: string |
Credentials: &config.ServerCredentials{Password: string} |
DB: int |
DatabaseId: int |
TLSConfig: *tls.Config |
UseTLS: true |
DialTimeout: time.Duration |
RequestTimeout: time.Duration |
ReadTimeout: time.Duration |
RequestTimeout: time.Duration |
WriteTimeout: time.Duration |
RequestTimeout: time.Duration |
MaxRetries: int |
ConnectionBackoff: &config.ConnectionBackoffStrategy{NumberOfRetries: int} |
MinRetryBackoff: time.Duration |
ConnectionBackoff: &config.ConnectionBackoffStrategy{Factor: int, ExponentBase: int} |
MaxRetryBackoff: time.Duration |
ConnectionBackoff: &config.ConnectionBackoffStrategy{Factor: int, ExponentBase: int} |
ClientName: string |
ClientName: string |
ReadFrom: ReadFrom |
ReadFrom: config.ReadFrom.Replica / config.ReadFrom.PreferReplica / config.ReadFrom.AZAffinity / config.ReadFrom.AZAffinityReplicasAndPrimary Read about AZ affinity
|
LazyConnect: bool |
LazyConnect: bool |
Advanced configuration
Both Standalone and Cluster modes support advanced configuration options:
// Standalone mode
client, err := glide.NewClient(&config.ClientConfiguration{
Addresses: []config.NodeAddress{{Host: "localhost", Port: 6379}},
RequestTimeout: 500 * time.Millisecond,
UseTLS: true,
ClientName: "my-client",
})
// Cluster mode
clusterClient, err := glide.NewClusterClient(&config.ClusterClientConfiguration{
Addresses: []config.NodeAddress{{Host: "localhost", Port: 6379}},
RequestTimeout: 500 * time.Millisecond,
UseTLS: true,
ClientName: "my-cluster-client",
})
Below is a comprehensive list of common Valkey commands and how they are implemented in both go-redis and Glide.
SET & GET
The SET
command stores a key-value pair in Valkey, while GET
retrieves the value associated with a key.
- Both go-redis and Glide support these commands with similar syntax.
go-redis
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val) // "key value"
// With expiration
err = rdb.Set(ctx, "key", "value", time.Hour).Err()
Glide
_, err := client.Set(ctx, "key", "value")
if err != nil {
panic(err)
}
val, err := client.Get(ctx, "key")
if err != nil {
panic(err)
}
fmt.Println("key", val.Value()) // "key value"
// With expiration
import "github.com/valkey-io/valkey-glide/go/v2/options"
_, err = client.SetWithOptions(ctx, "key", "value", options.SetOptions{
Expiry: &options.Expiry{
Type: options.Seconds,
Count: 3600,
},
})
SETEX (Set with Expiry)
The SETEX
command sets a key with an expiration time in seconds.
- In go-redis, this is a dedicated function.
- In Glide, expiration is handled using options within the
Set()
command.
go-redis
err := rdb.SetEx(ctx, "key", "value", time.Hour).Err()
if err != nil {
panic(err)
}
Glide
import "github.com/valkey-io/valkey-glide/go/v2/options"
_, err := client.SetWithOptions(ctx, "key", "value", options.SetOptions{
Expiry: &options.Expiry{
Type: options.Seconds,
Count: 3600,
},
})
if err != nil {
panic(err)
}
SETNX (Set if Not Exists)
The SETNX
command sets a key only if it does not already exist.
- In go-redis, this is a dedicated function that returns true if the key was set, false if the key already exists.
- In Glide, this is handled using options within the
Set()
command.
go-redis
result, err := rdb.SetNX(ctx, "key", "value", 0).Result()
if err != nil {
panic(err)
}
fmt.Println(result) // true if key was set, false if key exists
Glide
import "github.com/valkey-io/valkey-glide/go/v2/options"
result, err := client.SetWithOptions(ctx, "key", "value", options.SetOptions{
ConditionalSet: options.OnlyIfDoesNotExist,
})
if err != nil {
panic(err)
}
// Returns "OK" if key was set, nil if key exists
fmt.Println(result.Value()) // "OK" or empty if nil
MSET & MGET (Multiple Set/Get)
The MSET
command sets multiple key-value pairs in a single operation, while MGET
retrieves values for multiple keys.
- In go-redis,
MSet()
accepts a map or key-value pairs as arguments. - In Glide,
MSet()
accepts a map with key-value pairs. - For
MGet()
, go-redis accepts multiple keys as arguments, while Glide requires a slice of keys.
go-redis
// Multiple set
err := rdb.MSet(ctx, map[string]interface{}{
"key1": "value1",
"key2": "value2",
}).Err()
if err != nil {
panic(err)
}
// Multiple get
values, err := rdb.MGet(ctx, "key1", "key2").Result()
if err != nil {
panic(err)
}
fmt.Println(values) // [value1 value2]
Glide
// Multiple set
_, err := client.MSet(ctx, map[string]string{
"key1": "value1",
"key2": "value2",
})
if err != nil {
panic(err)
}
// Multiple get
values, err := client.MGet(ctx, []string{"key1", "key2"})
if err != nil {
panic(err)
}
// values is []models.Result[string]
for _, val := range values {
if val.IsNil() {
fmt.Println("nil")
} else {
fmt.Println(val.Value())
}
}
INCR & DECR
The INCR
command increments the value of a key by 1, while DECR
decrements it by 1.
- Both go-redis and Glide support these commands in the same way.
- The key must contain an integer value, otherwise an error will be returned.
go-redis
result, err := rdb.Incr(ctx, "counter").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1
result, err = rdb.Decr(ctx, "counter").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 0
Glide
result, err := client.Incr(ctx, "counter")
if err != nil {
panic(err)
}
fmt.Println(result) // 1
result, err = client.Decr(ctx, "counter")
if err != nil {
panic(err)
}
fmt.Println(result) // 0
INCRBY & DECRBY
The INCRBY
command increases the value of a key by a specified amount, while DECRBY
decreases it by a specified amount.
- Both go-redis and Glide support these commands in the same way.
- The key must contain an integer value, otherwise an error will be returned.
go-redis
result, err := rdb.IncrBy(ctx, "counter", 5).Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 5
result, err = rdb.DecrBy(ctx, "counter", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 3
Glide
result, err := client.IncrBy(ctx, "counter", 5)
if err != nil {
panic(err)
}
fmt.Println(result) // 5
result, err = client.DecrBy(ctx, "counter", 2)
if err != nil {
panic(err)
}
fmt.Println(result) // 3
APPEND
The APPEND
command appends a value to the end of an existing string stored at a key.
- Both go-redis and Glide support this command in the same way.
- Returns the length of the string after the append operation.
go-redis
err := rdb.Set(ctx, "greeting", "Hello", 0).Err()
if err != nil {
panic(err)
}
length, err := rdb.Append(ctx, "greeting", " World").Result()
if err != nil {
panic(err)
}
fmt.Println(length) // 11
result, err := rdb.Get(ctx, "greeting").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "Hello World"
Glide
_, err := client.Set(ctx, "greeting", "Hello")
if err != nil {
panic(err)
}
length, err := client.Append(ctx, "greeting", " World")
if err != nil {
panic(err)
}
fmt.Println(length) // 11
result, err := client.Get(ctx, "greeting")
if err != nil {
panic(err)
}
fmt.Println(result.Value()) // "Hello World"
GETRANGE & SETRANGE
The GETRANGE
command retrieves a substring from a string value stored at a key, while SETRANGE
overwrites part of a string at a key starting at a specified offset.
- Both go-redis and Glide support these commands in the same way.
go-redis
err := rdb.Set(ctx, "key", "Hello World", 0).Err()
if err != nil {
panic(err)
}
result, err := rdb.GetRange(ctx, "key", 0, 4).Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "Hello"
length, err := rdb.SetRange(ctx, "key", 6, "Redis").Result()
if err != nil {
panic(err)
}
fmt.Println(length) // 11
updated, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println(updated) // "Hello Redis"
Glide
_, err := client.Set(ctx, "key", "Hello World")
if err != nil {
panic(err)
}
result, err := client.GetRange(ctx, "key", 0, 4)
if err != nil {
panic(err)
}
fmt.Println(result) // "Hello"
length, err := client.SetRange(ctx, "key", 6, "Redis")
if err != nil {
panic(err)
}
fmt.Println(length) // 11
updated, err := client.Get(ctx, "key")
if err != nil {
panic(err)
}
fmt.Println(updated.Value()) // "Hello Redis"
DEL (Delete)
The DEL
command removes one or more keys from Valkey.
- In go-redis,
Del()
accepts multiple keys as separate arguments. - In Glide,
Del()
requires a slice of keys.
go-redis
result, err := rdb.Del(ctx, "key1", "key2").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (number of keys deleted)
Glide
result, err := client.Del(ctx, []string{"key1", "key2"})
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (number of keys deleted)
EXISTS
The EXISTS
command checks if one or more keys exist in Valkey.
- In go-redis,
Exists()
accepts multiple keys as separate arguments and returns the number of keys that exist. - In Glide,
Exists()
requires a slice of keys and also returns the number of keys that exist.
go-redis
result, err := rdb.Exists(ctx, "existKey", "nonExistKey").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1 (number of keys that exist)
Glide
result, err := client.Exists(ctx, []string{"existKey", "nonExistKey"})
if err != nil {
panic(err)
}
fmt.Println(result) // 1 (number of keys that exist)
EXPIRE & TTL
The EXPIRE
command sets a time-to-live (TTL) for a key, after which it will be automatically deleted. The TTL
command returns the remaining time-to-live for a key.
- Both go-redis and Glide support these commands with similar syntax.
go-redis
result, err := rdb.Expire(ctx, "key", 10*time.Second).Result()
if err != nil {
panic(err)
}
fmt.Println(result) // true (success)
ttl, err := rdb.TTL(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println(ttl) // 10s (seconds remaining)
Glide
result, err := client.Expire(ctx, "key", 10*time.Second)
if err != nil {
panic(err)
}
fmt.Println(result) // true (success)
ttl, err := client.TTL(ctx, "key")
if err != nil {
panic(err)
}
fmt.Println(ttl) // 10 (seconds remaining)
KEYS & SCAN
The KEYS
command returns all keys matching a pattern, while SCAN
iterates through keys in a more efficient way for production use.
-
KEYS
is not recommended for production use as it blocks the server until completion. -
SCAN
is the preferred method for iterating through keys in production environments. - In Glide, the cursor returned by
Scan()
needs to be handled using themodels.Cursor
type.
go-redis
// KEYS (not recommended for production)
allKeys, err := rdb.Keys(ctx, "*").Result()
if err != nil {
panic(err)
}
// SCAN (recommended for production)
var cursor uint64
var keys []string
for {
var err error
keys, cursor, err = rdb.Scan(ctx, cursor, "*", 10).Result()
if err != nil {
panic(err)
}
if len(keys) > 0 {
fmt.Println("SCAN iteration:", keys)
}
if cursor == 0 {
break
}
}
Glide
import "github.com/valkey-io/valkey-glide/go/v2/models"
// KEYS (not recommended for production)
allKeys, err := client.Keys(ctx, "*")
if err != nil {
panic(err)
}
// SCAN (recommended for production)
cursor := models.NewCursor("0")
for {
result, err := client.Scan(ctx, cursor)
if err != nil {
panic(err)
}
keys := result.Data
if len(keys) > 0 {
fmt.Println("SCAN iteration:", keys)
}
cursor = result.Cursor
if cursor.IsFinished() {
break
}
}
RENAME & RENAMENX
The RENAME
command renames a key, while RENAMENX
renames a key only if the new key does not already exist.
- Both go-redis and Glide support these commands with similar syntax.
go-redis
err := rdb.Set(ctx, "oldkey", "value", 0).Err()
if err != nil {
panic(err)
}
result, err := rdb.Rename(ctx, "oldkey", "newkey").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "OK"
err = rdb.Set(ctx, "key1", "value1", 0).Err()
if err != nil {
panic(err)
}
success, err := rdb.RenameNX(ctx, "key1", "key2").Result()
if err != nil {
panic(err)
}
fmt.Println(success) // true (success)
Glide
_, err := client.Set(ctx, "oldkey", "value")
if err != nil {
panic(err)
}
result, err := client.Rename(ctx, "oldkey", "newkey")
if err != nil {
panic(err)
}
fmt.Println(result) // "OK"
_, err = client.Set(ctx, "key1", "value1")
if err != nil {
panic(err)
}
success, err := client.RenameNX(ctx, "key1", "key2")
if err != nil {
panic(err)
}
fmt.Println(success) // true (success)
HSET & HGET
The HSET
command sets field-value pairs in a hash stored at a key, while HGET
retrieves the value of a specific field.
- In go-redis,
HSet()
accepts field-value pairs as separate arguments or a map. - In Glide,
HSet()
accepts a map with field-value pairs.
go-redis
// Set multiple fields
result, err := rdb.HSet(ctx, "hash", "key1", "1", "key2", "2").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (fields added)
// Get a single field
value, err := rdb.HGet(ctx, "hash", "key1").Result()
if err != nil {
panic(err)
}
fmt.Println(value) // "1"
Glide
// Set multiple fields
result, err := client.HSet(ctx, "hash", map[string]string{
"key1": "1",
"key2": "2",
})
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (fields added)
// Get a single field
value, err := client.HGet(ctx, "hash", "key1")
if err != nil {
panic(err)
}
fmt.Println(value.Value()) // "1"
HMSET & HMGET
The HMSET
command sets multiple field-value pairs in a hash, while HMGET
retrieves values for multiple fields.
- In go-redis,
HMSet()
accepts either field-value pairs as arguments or a map. - In Glide, there is no separate
HMSet()
method; instead,HSet()
is used for setting multiple fields. - For
HMGet()
, go-redis accepts multiple fields as arguments, while Glide requires a slice of fields.
go-redis
// Set multiple fields
err := rdb.HMSet(ctx, "hash", map[string]interface{}{
"key1": "1",
"key2": "2",
}).Err()
if err != nil {
panic(err)
}
// Get multiple fields
values, err := rdb.HMGet(ctx, "hash", "key1", "key2").Result()
if err != nil {
panic(err)
}
fmt.Println(values) // ["1", "2"]
Glide
// Set multiple fields (same as HSet in Glide)
_, err := client.HSet(ctx, "hash", map[string]string{
"key1": "1",
"key2": "2",
})
if err != nil {
panic(err)
}
// Get multiple fields
values, err := client.HMGet(ctx, "hash", []string{"key1", "key2"})
if err != nil {
panic(err)
}
// values is []models.Result[string]
for _, val := range values {
if val.IsNil() {
fmt.Println("nil")
} else {
fmt.Println(val.Value())
}
}
HGETALL
The HGETALL
command retrieves all field-value pairs from a hash.
- Both go-redis and Glide support this command in the same way.
- Returns a map with field names as keys and their values.
go-redis
err := rdb.HSet(ctx, "user", map[string]interface{}{
"name": "John",
"age": "30",
}).Err()
if err != nil {
panic(err)
}
user, err := rdb.HGetAll(ctx, "user").Result()
if err != nil {
panic(err)
}
fmt.Println(user) // map[name:John age:30]
Glide
_, err := client.HSet(ctx, "user", map[string]string{
"name": "John",
"age": "30",
})
if err != nil {
panic(err)
}
user, err := client.HGetAll(ctx, "user")
if err != nil {
panic(err)
}
fmt.Println(user) // map[name:John age:30]
HDEL & HEXISTS
The HDEL
command removes one or more fields from a hash, while HEXISTS
checks if a field exists in a hash.
- In go-redis,
HDel()
accepts multiple fields as separate arguments. - In Glide,
HDel()
requires a slice of fields.
go-redis
result, err := rdb.HDel(ctx, "hash", "field1", "field2").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (fields deleted)
exists, err := rdb.HExists(ctx, "hash", "field1").Result()
if err != nil {
panic(err)
}
fmt.Println(exists) // false
Glide
result, err := client.HDel(ctx, "hash", []string{"field1", "field2"})
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (fields deleted)
exists, err := client.HExists(ctx, "hash", "field1")
if err != nil {
panic(err)
}
fmt.Println(exists) // false
LPUSH & RPUSH
The LPUSH
command adds elements to the head of a list, while RPUSH
adds elements to the tail.
- In go-redis, these commands accept multiple elements as separate arguments.
- In Glide, these commands require a slice of elements.
go-redis
result, err := rdb.LPush(ctx, "list", "element1", "element2").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (list length)
result, err = rdb.RPush(ctx, "list", "element3", "element4").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 4 (list length)
Glide
result, err := client.LPush(ctx, "list", []string{"element1", "element2"})
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (list length)
result, err = client.RPush(ctx, "list", []string{"element3", "element4"})
if err != nil {
panic(err)
}
fmt.Println(result) // 4 (list length)
LPOP & RPOP
The LPOP
command removes and returns an element from the head of a list, while RPOP
removes and returns an element from the tail.
- Both go-redis and Glide support these commands with similar syntax.
go-redis
value, err := rdb.LPop(ctx, "list").Result()
if err != nil {
panic(err)
}
fmt.Println(value) // "element2"
value, err = rdb.RPop(ctx, "list").Result()
if err != nil {
panic(err)
}
fmt.Println(value) // "element4"
Glide
value, err := client.LPop(ctx, "list")
if err != nil {
panic(err)
}
fmt.Println(value.Value()) // "element2"
value, err = client.RPop(ctx, "list")
if err != nil {
panic(err)
}
fmt.Println(value.Value()) // "element4"
LRANGE
The LRANGE
command returns a range of elements from a list.
- Both go-redis and Glide support this command with similar syntax.
go-redis
values, err := rdb.LRange(ctx, "list", 0, -1).Result()
if err != nil {
panic(err)
}
fmt.Println(values) // ["element1", "element3"]
Glide
values, err := client.LRange(ctx, "list", 0, -1)
if err != nil {
panic(err)
}
fmt.Println(values) // ["element1", "element3"]
SADD & SMEMBERS
The SADD
command adds members to a set, while SMEMBERS
returns all members of a set.
- In go-redis,
SAdd()
accepts multiple members as separate arguments. - In Glide,
SAdd()
requires a slice of members.
go-redis
result, err := rdb.SAdd(ctx, "set", "member1", "member2").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (members added)
members, err := rdb.SMembers(ctx, "set").Result()
if err != nil {
panic(err)
}
fmt.Println(members) // ["member1", "member2"]
Glide
result, err := client.SAdd(ctx, "set", []string{"member1", "member2"})
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (members added)
members, err := client.SMembers(ctx, "set")
if err != nil {
panic(err)
}
// Convert map[string]struct{} to slice for printing
var memberSlice []string
for member := range members {
memberSlice = append(memberSlice, member)
}
fmt.Println(memberSlice) // ["member1", "member2"]
SREM & SISMEMBER
The SREM
command removes members from a set, while SISMEMBER
checks if a member exists in a set.
- In go-redis,
SRem()
accepts multiple members as separate arguments. - In Glide,
SRem()
requires a slice of members.
go-redis
result, err := rdb.SRem(ctx, "set", "member1").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1 (members removed)
exists, err := rdb.SIsMember(ctx, "set", "member1").Result()
if err != nil {
panic(err)
}
fmt.Println(exists) // false
Glide
result, err := client.SRem(ctx, "set", []string{"member1"})
if err != nil {
panic(err)
}
fmt.Println(result) // 1 (members removed)
exists, err := client.SIsMember(ctx, "set", "member1")
if err != nil {
panic(err)
}
fmt.Println(exists) // false
ZADD & ZRANGE
The ZADD
command adds members with scores to a sorted set, while ZRANGE
returns a range of members.
- In go-redis,
ZAdd()
accepts score-member pairs. - In Glide,
ZAdd()
accepts a map with member-score pairs.
go-redis
import "github.com/redis/go-redis/v9"
result, err := rdb.ZAdd(ctx, "zset", redis.Z{Score: 1, Member: "member1"}, redis.Z{Score: 2, Member: "member2"}).Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (members added)
members, err := rdb.ZRange(ctx, "zset", 0, -1).Result()
if err != nil {
panic(err)
}
fmt.Println(members) // ["member1", "member2"]
Glide
result, err := client.ZAdd(ctx, "zset", map[string]float64{
"member1": 1.0,
"member2": 2.0,
})
if err != nil {
panic(err)
}
fmt.Println(result) // 2 (members added)
import "github.com/valkey-io/valkey-glide/go/v2/options"
members, err := client.ZRange(ctx, "zset", options.RangeByIndex{Start: 0, End: -1})
if err != nil {
panic(err)
}
fmt.Println(members) // ["member1", "member2"]
ZRANK & ZREVRANK
The ZRANK
command returns the rank of a member in a sorted set (lowest to highest), while ZREVRANK
returns the rank from highest to lowest.
- Both go-redis and Glide support these commands with similar syntax.
go-redis
rank, err := rdb.ZRank(ctx, "zset", "member1").Result()
if err != nil {
panic(err)
}
fmt.Println(rank) // 0
revRank, err := rdb.ZRevRank(ctx, "zset", "member1").Result()
if err != nil {
panic(err)
}
fmt.Println(revRank) // 1
Glide
rank, err := client.ZRank(ctx, "zset", "member1")
if err != nil {
panic(err)
}
fmt.Println(rank.Value()) // 0
revRank, err := client.ZRevRank(ctx, "zset", "member1")
if err != nil {
panic(err)
}
fmt.Println(revRank.Value()) // 1
ZREM & ZSCORE
The ZREM
command removes members from a sorted set, while ZSCORE
returns the score of a member.
- In go-redis,
ZRem()
accepts multiple members as separate arguments. - In Glide,
ZRem()
requires a slice of members.
go-redis
result, err := rdb.ZRem(ctx, "zset", "member1").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1 (members removed)
score, err := rdb.ZScore(ctx, "zset", "member2").Result()
if err != nil {
panic(err)
}
fmt.Println(score) // 2.0
Glide
result, err := client.ZRem(ctx, "zset", []string{"member1"})
if err != nil {
panic(err)
}
fmt.Println(result) // 1 (members removed)
score, err := client.ZScore(ctx, "zset", "member2")
if err != nil {
panic(err)
}
fmt.Println(score.Value()) // 2.0
Transactions (MULTI/EXEC)
Transactions allow you to execute multiple commands atomically.
- In go-redis, transactions are handled using
TxPipeline()
. - In Glide, transactions are handled using batch operations with
Exec()
.
go-redis
pipe := rdb.TxPipeline()
pipe.Set(ctx, "key1", "value1", 0)
pipe.Set(ctx, "key2", "value2", 0)
pipe.Incr(ctx, "counter")
results, err := pipe.Exec(ctx)
if err != nil {
panic(err)
}
fmt.Println(len(results)) // 3 (commands executed)
Glide
import "github.com/valkey-io/valkey-glide/go/v2/pipeline"
batch := pipeline.NewStandaloneBatch()
batch.Set("key1", "value1")
batch.Set("key2", "value2")
batch.Incr("counter")
results, err := client.Exec(ctx, batch, false)
if err != nil {
panic(err)
}
fmt.Println(len(results)) // 3 (commands executed)
EVAL / EVALSHA
The EVAL
command executes Lua scripts, while EVALSHA
executes scripts by their SHA1 hash.
- Both go-redis and Glide support Lua script execution.
- In Glide, scripts are managed using the
Script
type andInvokeScript()
method.
go-redis
script := `
local key = KEYS[1]
local value = ARGV[1]
redis.call('SET', key, value)
return redis.call('GET', key)
`
result, err := rdb.Eval(ctx, script, []string{"mykey"}, "myvalue").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "myvalue"
Glide
import "github.com/valkey-io/valkey-glide/go/v2/options"
scriptCode := `
local key = KEYS[1]
local value = ARGV[1]
redis.call('SET', key, value)
return redis.call('GET', key)
`
script := options.NewScript(scriptCode)
result, err := client.InvokeScriptWithOptions(ctx, script, options.ScriptOptions{
Keys: []string{"mykey"},
Args: []string{"myvalue"},
})
if err != nil {
panic(err)
}
fmt.Println(result) // "myvalue"
Custom Commands
Both libraries support executing custom or arbitrary Valkey commands.
- In go-redis, use
Do()
method. - In Glide, use
CustomCommand()
method.
go-redis
result, err := rdb.Do(ctx, "PING").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "PONG"
// Custom command with arguments
result, err = rdb.Do(ctx, "SET", "customkey", "customvalue").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "OK"
Glide
result, err := client.CustomCommand(ctx, []string{"PING"})
if err != nil {
panic(err)
}
fmt.Println(result) // "PONG"
// Custom command with arguments
result, err = client.CustomCommand(ctx, []string{"SET", "customkey", "customvalue"})
if err != nil {
panic(err)
}
fmt.Println(result) // "OK"
AUTH
Authentication is typically handled during connection setup, but can also be done explicitly.
- In go-redis, authentication is usually set in the client options or can be done with
Auth()
. - In Glide, authentication is set in the client configuration during connection setup.
go-redis
// During connection setup
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Username: "user",
Password: "password",
})
// Or explicitly after connection
result, err := rdb.Auth(ctx, "password").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // "OK"
Glide
// During connection setup (recommended)
client, err := glide.NewClient(&config.ClientConfiguration{
Addresses: []config.NodeAddress{
{Host: "localhost", Port: 6379},
},
Credentials: &config.ServerCredentials{
Username: "user",
Password: "password",
},
})
// Authentication is handled automatically during connection
Error handling differs between the two libraries:
go-redis
val, err := rdb.Get(ctx, "nonexistent").Result()
if err == redis.Nil {
fmt.Println("Key does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("Value:", val)
}
Glide
val, err := client.Get(ctx, "nonexistent")
if err != nil {
panic(err)
}
if val.IsNil() {
fmt.Println("Key does not exist")
} else {
fmt.Println("Value:", val.Value())
}
Close / Disconnect
Properly closing connections is important to free up resources and avoid connection leaks.
- In go-redis, you call
Close()
on the client and handle any potential errors. - In Glide, you call
Close()
on the client (no error return).
go-redis
// Close connection
err := rdb.Close()
if err != nil {
panic(err)
}
// For cluster connections
err = cluster.Close()
if err != nil {
panic(err)
}
Glide
// Close connection (works for both standalone and cluster)
client.Close()
Below is a comprehensive chart comparing common Valkey commands between go-redis and Valkey Glide:
Command | go-redis | Valkey Glide |
---|---|---|
Connection | ||
Connect | redis.NewClient(&redis.Options{Addr: "localhost:6379"}) |
glide.NewClient(&config.ClientConfiguration{Addresses: []config.NodeAddress{{Host: "localhost", Port: 6379}}}) |
Cluster | redis.NewClusterClient(&redis.ClusterOptions{Addrs: []string{"127.0.0.1:6379"}}) |
glide.NewClusterClient(&config.ClusterClientConfiguration{Addresses: []config.NodeAddress{{Host: "127.0.0.1", Port: 6379}}}) |
Auth | rdb.Auth(ctx, "password") |
Set in config.ServerCredentials{Password: "password"} during connection |
Select DB | rdb.Select(ctx, 1) |
Set DatabaseId: 1 in configuration |
Strings | ||
SET | rdb.Set(ctx, "key", "val", 0) |
client.Set(ctx, "key", "val") |
GET | rdb.Get(ctx, "key") |
client.Get(ctx, "key") |
SETEX | rdb.SetEx(ctx, "key", "val", time.Hour) |
client.SetWithOptions(ctx, "key", "val", options.SetOptions{Expiry: &options.Expiry{Type: options.Seconds, Count: 3600}}) |
SETNX | rdb.SetNX(ctx, "key", "val", 0) |
client.SetWithOptions(ctx, "key", "val", options.SetOptions{ConditionalSet: options.OnlyIfDoesNotExist}) |
MSET | rdb.MSet(ctx, map[string]interface{}{"k1": "v1"}) |
client.MSet(ctx, map[string]string{"k1": "v1"}) |
MGET | rdb.MGet(ctx, "key1", "key2") |
client.MGet(ctx, []string{"key1", "key2"}) |
INCR | rdb.Incr(ctx, "counter") |
client.Incr(ctx, "counter") |
DECR | rdb.Decr(ctx, "counter") |
client.Decr(ctx, "counter") |
INCRBY | rdb.IncrBy(ctx, "counter", 5) |
client.IncrBy(ctx, "counter", 5) |
DECRBY | rdb.DecrBy(ctx, "counter", 5) |
client.DecrBy(ctx, "counter", 5) |
APPEND | rdb.Append(ctx, "key", "val") |
client.Append(ctx, "key", "val") |
GETRANGE | rdb.GetRange(ctx, "key", 0, 3) |
client.GetRange(ctx, "key", 0, 3) |
SETRANGE | rdb.SetRange(ctx, "key", 0, "val") |
client.SetRange(ctx, "key", 0, "val") |
Keys | ||
DEL | rdb.Del(ctx, "key1", "key2") |
client.Del(ctx, []string{"key1", "key2"}) |
EXISTS | rdb.Exists(ctx, "key1", "key2") |
client.Exists(ctx, []string{"key1", "key2"}) |
EXPIRE | rdb.Expire(ctx, "key", 10*time.Second) |
client.Expire(ctx, "key", 10*time.Second) |
TTL | rdb.TTL(ctx, "key") |
client.TTL(ctx, "key") |
KEYS | rdb.Keys(ctx, "pattern") |
client.Keys(ctx, "pattern") |
SCAN | rdb.Scan(ctx, cursor, "*", 10) |
client.Scan(ctx, cursor) |
RENAME | rdb.Rename(ctx, "old", "new") |
client.Rename(ctx, "old", "new") |
RENAMENX | rdb.RenameNX(ctx, "old", "new") |
client.RenameNX(ctx, "old", "new") |
Hashes | ||
HSET | rdb.HSet(ctx, "hash", "k1", "v1", "k2", "v2") |
client.HSet(ctx, "hash", map[string]string{"k1": "v1", "k2": "v2"}) |
HGET | rdb.HGet(ctx, "hash", "field") |
client.HGet(ctx, "hash", "field") |
HMSET | rdb.HMSet(ctx, "hash", map[string]interface{}{"k1": "v1"}) |
client.HSet(ctx, "hash", map[string]string{"k1": "v1"}) |
HMGET | rdb.HMGet(ctx, "hash", "k1", "k2") |
client.HMGet(ctx, "hash", []string{"k1", "k2"}) |
HGETALL | rdb.HGetAll(ctx, "hash") |
client.HGetAll(ctx, "hash") |
HDEL | rdb.HDel(ctx, "hash", "k1", "k2") |
client.HDel(ctx, "hash", []string{"k1", "k2"}) |
HEXISTS | rdb.HExists(ctx, "hash", "field") |
client.HExists(ctx, "hash", "field") |
Lists | ||
LPUSH | rdb.LPush(ctx, "list", "a", "b") |
client.LPush(ctx, "list", []string{"a", "b"}) |
RPUSH | rdb.RPush(ctx, "list", "a", "b") |
client.RPush(ctx, "list", []string{"a", "b"}) |
LPOP | rdb.LPop(ctx, "list") |
client.LPop(ctx, "list") |
RPOP | rdb.RPop(ctx, "list") |
client.RPop(ctx, "list") |
LRANGE | rdb.LRange(ctx, "list", 0, -1) |
client.LRange(ctx, "list", 0, -1) |
Sets | ||
SADD | rdb.SAdd(ctx, "set", "a", "b") |
client.SAdd(ctx, "set", []string{"a", "b"}) |
SMEMBERS | rdb.SMembers(ctx, "set") |
client.SMembers(ctx, "set") |
SREM | rdb.SRem(ctx, "set", "a", "b") |
client.SRem(ctx, "set", []string{"a", "b"}) |
SISMEMBER | rdb.SIsMember(ctx, "set", "a") |
client.SIsMember(ctx, "set", "a") |
Sorted Sets | ||
ZADD | rdb.ZAdd(ctx, "zset", redis.Z{Score: 1, Member: "a"}, redis.Z{Score: 2, Member: "b"}) |
client.ZAdd(ctx, "zset", map[string]float64{"a": 1.0, "b": 2.0}) |
ZRANGE | rdb.ZRange(ctx, "zset", 0, -1) |
client.ZRange(ctx, "zset", options.RangeByIndex{Start: 0, End: -1}) |
ZRANGE with scores | rdb.ZRangeWithScores(ctx, "zset", 0, -1) |
client.ZRangeWithScores(ctx, "zset", options.RangeByIndex{Start: 0, End: -1}) |
ZREM | rdb.ZRem(ctx, "zset", "a", "b") |
client.ZRem(ctx, "zset", []string{"a", "b"}) |
ZSCORE | rdb.ZScore(ctx, "zset", "a") |
client.ZScore(ctx, "zset", "a") |
ZRANK | rdb.ZRank(ctx, "zset", "a") |
client.ZRank(ctx, "zset", "a") |
ZREVRANK | rdb.ZRevRank(ctx, "zset", "a") |
client.ZRevRank(ctx, "zset", "a") |
Transactions | ||
MULTI/EXEC | pipe := rdb.TxPipeline(); pipe.Set(ctx, "k", "v", 0); pipe.Get(ctx, "k"); pipe.Exec(ctx) |
batch := pipeline.NewStandaloneBatch(); batch.Set("k", "v"); batch.Get("k"); client.Exec(ctx, batch, false) |
Lua Scripts | ||
EVAL | rdb.Eval(ctx, script, []string{"key"}, "arg") |
client.InvokeScriptWithOptions(ctx, options.NewScript(script), options.ScriptOptions{Keys: []string{"key"}, Args: []string{"arg"}}) |
EVALSHA | rdb.EvalSha(ctx, sha, []string{"key"}, "arg") |
client.InvokeScriptWithOptions(ctx, options.NewScript(script), options.ScriptOptions{Keys: []string{"key"}, Args: []string{"arg"}}) |
Custom Commands | ||
Raw Command | rdb.Do(ctx, "SET", "key", "value") |
client.CustomCommand(ctx, []string{"SET", "key", "value"}) |
Connection Management | ||
Close | rdb.Close() |
client.Close() |