-
Notifications
You must be signed in to change notification settings - Fork 112
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 existsGlide
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 nilMSET & 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) // 0Glide
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) // 0INCRBY & 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) // 3Glide
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) // 3APPEND
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.
-
KEYSis not recommended for production use as it blocks the server until completion. -
SCANis the preferred method for iterating through keys in production environments. - In Glide, the cursor returned by
Scan()needs to be handled using themodels.Cursortype.
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) // falseGlide
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) // falseLPUSH & 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) // falseGlide
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) // falseZADD & 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) // 1Glide
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()) // 1ZREM & 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.0Glide
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.0Transactions (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
Scripttype 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 connectionError 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() |