- 
                Notifications
    You must be signed in to change notification settings 
- Fork 112
Migration Guide redis‐py
This guide provides a comprehensive comparison of how to migrate from redis-py to Valkey Glide, with side-by-side code examples to make the transition as smooth as possible.
pip install valkey-glide- redis-py offers multiple constructors for different connection configurations
- Glide uses a 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 Glide Wiki - Python.
Standalone Mode
redis-py
import redis
# Simple connection
r = redis.Redis(host='localhost', port=6379, db=0)
# With options
r_with_options = redis.Redis(
    host='localhost',
    port=6379,
    username='user',
    password='password',
    decode_responses=True  # Return strings instead of bytes
)Glide
from glide import GlideClient, GlideClientConfiguration, NodeAddress, ServerCredentials
# Simple connection
addresses = [NodeAddress("localhost", 6379)]
client_config = GlideClientConfiguration(addresses)
client = await GlideClient.create(client_config)
# With options
addresses = [NodeAddress("localhost", 6379)]
client_config = GlideClientConfiguration(
    addresses,
    use_tls=True,
    credentials=ServerCredentials(username="user", password="password"),
    read_from=ReadFrom.AZ_AFFINITY,
    request_timeout=2000,
    connection_backoff=ConnectionBackoffStrategy(
        number_of_retries=5,
        factor=2,
        exponent_base=2,
        jitter_percent=10
    ),
    advanced_configuration=AdvancedGlideClientConfiguration(
        connection_timeout=5000,
        tls_advanced_configuration=TlsAdvancedConfiguration(
            use_insecure_tls=False
        )
    )
)
client_with_options = await GlideClient.create(client_config)Cluster Mode
redis-py
from redis.cluster import RedisCluster
# Simple connection
rc = RedisCluster(
    startup_nodes=[
        {"host": "127.0.0.1", "port": 6379},
        {"host": "127.0.0.1", "port": 6380}
    ],
    decode_responses=True
)
# With options
rc_with_options = RedisCluster(
    startup_nodes=[
        {"host": "127.0.0.1", "port": 6379},
        {"host": "127.0.0.1", "port": 6380}
    ],
    password="password",
    decode_responses=True
)Glide
from glide import GlideClusterClient, GlideClusterClientConfiguration, NodeAddress, ServerCredentials
# Simple connection
addresses = [
    NodeAddress("127.0.0.1", 6379),
    NodeAddress("127.0.0.1", 6380)
]
client_config = GlideClusterClientConfiguration(addresses)
client = await GlideClusterClient.create(client_config)
# With options
addresses = [
    NodeAddress("127.0.0.1", 6379),
    NodeAddress("127.0.0.1", 6380)
]
credentials = ServerCredentials(password="password")
client_config = GlideClusterClientConfiguration(
    addresses,
    use_tls=True,
    credentials=credentials,
    read_from=ReadFrom.AZ_AFFINITY,
    request_timeout=2000,
    connection_backoff=ConnectionBackoffStrategy(
        number_of_retries=5,
        factor=2,
        exponent_base=2,
        jitter_percent=10
    ),
    advanced_configuration=AdvancedGlideClusterClientConfiguration(
        connection_timeout=5000,
        tls_advanced_configuration=TlsAdvancedConfiguration(
            use_insecure_tls=False
        )
    )
)
client_with_options = await GlideClusterClient.create(client_config)Constructor Parameters Comparison
The table below compares redis-py constructors with Glide configuration parameters:
| redis-py Parameter | Equivalent Glide Configuration | 
|---|---|
| host: str | addresses: [NodeAddress(host="host", port=port)] | 
| port: int | addresses: [NodeAddress(host="host", port=port)] | 
| db: int | - Use client.select(db)after connection | 
| username: str | credentials: ServerCredentials(username="username") | 
| password: str | credentials: ServerCredentials(password="password") | 
| socket_timeout: float | request_timeout: int(in milliseconds) | 
| socket_connect_timeout: float | advanced_configuration: AdvancedGlideClientConfiguration(connection_timeout=timeout) | 
| decode_responses: bool | Use .decode()on returned bytes | 
| retry_on_timeout: bool | connection_backoff: ConnectionBackoffStrategy(number_of_retries=retries, factor=factor, exponent_base=base, jitter_percent=percent) | 
| ssl: bool | use_tls: bool | 
| client_name: str | client_name: str | 
| read_from_replicas: bool | read_from: ReadFrom.REPLICA/read_from: ReadFrom.PREFER_REPLICA/read_from: ReadFrom.AZ_AFFINITY/read_from: ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARYRead about AZ affinity | 
| lazy_connect: bool | lazy_connect: bool | 
Advanced configuration
Standalone Mode uses GlideClientConfiguration and Cluster Mode uses GlideClusterClientConfiguration, but the usage is similar:
# Standalone mode
client_config = GlideClientConfiguration(
    addresses=[NodeAddress(host="localhost", port=6379)],
    request_timeout=500  # 500ms timeout
)
client = await GlideClient.create(client_config)
# Cluster mode
cluster_config = GlideClusterClientConfiguration(
    addresses=[NodeAddress(host="localhost", port=6379)],
    request_timeout=500  # 500ms timeout
)
cluster_client = await GlideClusterClient.create(cluster_config)Below is a comprehensive list of common Redis commands and how they are implemented in both redis-py and Glide.
SET & GET
The SET command stores a key-value pair in Valkey, while GET retrieves the value associated with a key.
- Both redis-py and Glide support these commands in the same way.
- Note that redis-py can return strings if decode_responses=Trueis set, while Glide always returns bytes.
redis-py
await r.set('key', 'value')
val = await r.get('key')  # b"value" or "value" if decode_responses=True
# With options
await r.set('key', 'value', ex=60)  # Set with 60 second expiryGlide
await client.set('key', 'value')
val = await client.get('key')  # b"value"
# With options
from glide import ExpiryType
await client.set('key', 'value', expiry=ExpirySet(ExpiryType.SEC, 60))SETEX (Set with Expiry)
The SETEX command sets a key with an expiration time in seconds.
- In redis-py, this is a dedicated function.
- In Glide, expiration is handled using the ExpirySetclass within theset()command.
redis-py
await r.setex('key', 5, 'value')  # Set with 5 second expiryGlide
from glide import ExpiryType, ExpirySet
await client.set('key', 'value', expiry=ExpirySet(ExpiryType.SEC, 5))SETNX (Set if Not Exists)
The SETNX command sets a key only if it does not already exist.
- In redis-py, 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 the ConditionalChangeenum within theset()command.
redis-py
result = await r.setnx('key', 'value')  # Returns True if key was set, False if key existsGlide
from glide import ConditionalChange
result = await client.set('key', 'value', conditional_set=ConditionalChange.ONLY_IF_DOES_NOT_EXIST)
# Returns "OK" if key was set, None if key existsMSET & MGET (Multiple Set/Get)
The MSET command sets multiple key-value pairs in a single operation, while MGET retrieves values for multiple keys.
- Both redis-py and Glide support these commands in a similar way.
- For mget(), both libraries accept a list of keys.
redis-py
# Multiple set
await r.mset({'key1': 'value1', 'key2': 'value2'})
# Multiple get
values = await r.mget(['key1', 'key2'])  # [b'value1', b'value2'] or ["value1", "value2"] if decode_responses=TrueGlide
# Multiple set
await client.mset({'key1': 'value1', 'key2': 'value2'})
# Multiple get
values = await client.mget(['key1', 'key2'])  # [b'value1', b'value2']INCR & DECR
The INCR command increments the value of a key by 1, while DECR decrements it by 1.
- Both redis-py and Glide support these commands in the same way.
- The key must contain an integer value, otherwise an error will be returned.
redis-py
await r.incr('counter')  # counter = 1
await r.decr('counter')  # counter = 0Glide
await client.incr('counter')  # counter = 1
await client.decr('counter')  # counter = 0INCRBY & DECRBY
The INCRBY command increases the value of a key by a specified amount, while DECRBY decreases it by a specified amount.
- Both redis-py and Glide support these commands in the same way.
- The key must contain an integer value, otherwise an error will be returned.
redis-py
await r.incrby('counter', 5)  # 5
await r.decrby('counter', 2)  # 3Glide
await client.incrby('counter', 5)  # 5
await client.decrby('counter', 2)  # 3APPEND
The APPEND command appends a value to the end of an existing string stored at a key.
- Both redis-py and Glide support this command in the same way.
- Returns the length of the string after the append operation.
redis-py
await r.set('greeting', 'Hello')
await r.append('greeting', ' World')  # Returns length: 11
result = await r.get('greeting')  # b"Hello World" or "Hello World" if decode_responses=TrueGlide
await client.set('greeting', 'Hello')
await client.append('greeting', ' World')  # Returns length: 11
result = await client.get('greeting')  # b"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 redis-py and Glide support these commands in the same way.
- Note that in Glide, the method names are getrangeandsetrange(lowercase).
redis-py
await r.set('key', 'Hello World')
result = await r.getrange('key', 0, 4)  # b"Hello" or "Hello" if decode_responses=True
await r.setrange('key', 6, 'Redis')  # Returns length: 11
updated = await r.get('key')  # b"Hello Redis" or "Hello Redis" if decode_responses=TrueGlide
await client.set('key', 'Hello World')
result = await client.getrange('key', 0, 4)  # b"Hello"
await client.setrange('key', 6, 'Redis')  # Returns length: 11
updated = await client.get('key')  # b"Hello Redis"DEL (Delete)
The DEL command removes one or more keys from Valkey.
- In redis-py, delete()accepts multiple keys as separate arguments or as a list.
- In Glide, del()requires a list of keys.
redis-py
await r.delete('key1', 'key2')  # 2 (number of keys deleted)
# or
await r.delete(['key1', 'key2'])  # 2 (number of keys deleted)Glide
await client.delete(['key1', 'key2'])  # 2 (number of keys deleted)EXISTS
The EXISTS command checks if one or more keys exist in Valkey.
- In redis-py, exists()accepts multiple keys as separate arguments or as a list and returns the number of keys that exist.
- In Glide, exists()requires a list of keys and also returns the number of keys that exist.
redis-py
await r.exists('existKey', 'nonExistKey')  # 1 (number of keys that exist)
# or
await r.exists(['existKey', 'nonExistKey'])  # 1 (number of keys that exist)Glide
await client.exists(['existKey', 'nonExistKey'])  # 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.
- In redis-py, expire()returns True if successful, False if the key doesn't exist or couldn't be expired.
- In Glide, expire()returns True if successful, False otherwise.
redis-py
await r.expire('key', 10)  # True (success)
ttl = await r.ttl('key')  # 10 (seconds remaining)Glide
await client.expire('key', 10)  # True (success)
ttl = await client.ttl('key')  # 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()is a bytes object that needs to be converted to a string using.decode()or.toString().
redis-py
# KEYS (not recommended for production)
all_keys = await r.keys('*')
# SCAN (recommended for production)
cursor = '0'
while cursor != 0:
    cursor, keys = await r.scan(cursor=cursor, match='*')
    if keys:
        print(f'SCAN iteration: {", ".join(keys)}')Glide
# KEYS (not recommended for production)
all_keys = await client.keys('*')
# SCAN (recommended for production)
cursor = '0'
while cursor != '0':
    result = await client.scan(cursor)
    cursor = result[0].decode()  # or result[0].toString()
    
    keys = result[1]
    if keys:
        print(f'SCAN iteration: {", ".join([k.decode() for k in keys])}')RENAME & RENAMENX
The RENAME command renames a key, while RENAMENX renames a key only if the new key does not already exist.
- In redis-py, renamenx()returns True if successful, False if the target key already exists.
- In Glide, renamenx()returns True if successful, False if the target key already exists.
redis-py
await r.set('oldkey', 'value')
await r.rename('oldkey', 'newkey')  # True
await r.set('key1', 'value1')
result = await r.renamenx('key1', 'key2')  # True (success)Glide
await client.set('oldkey', 'value')
await client.rename('oldkey', 'newkey')  # "OK"
await client.set('key1', 'value1')
result = await client.renamenx('key1', 'key2')  # 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 redis-py, hset()can accept field-value pairs as separate arguments or as a mapping.
- In Glide, hset()accepts a key and a mapping of field-value pairs.
redis-py
# Set a single field
await r.hset('hash', 'key1', '1')  # 1 (field added)
# Set multiple fields
await r.hset('hash', mapping={'key1': '1', 'key2': '2'})  # 2 (fields added)
# Get a single field
value = await r.hget('hash', 'key1')  # b"1" or "1" if decode_responses=TrueGlide
# Set multiple fields
await client.hset('hash', {'key1': '1', 'key2': '2'})  # 2 (fields added)
# Get a single field
value = await client.hget('hash', 'key1')  # b"1"HMSET & HMGET
The HMSET command sets multiple field-value pairs in a hash, while HMGET retrieves values for multiple fields.
- In redis-py, hmset()accepts a mapping of field-value pairs.
- In Glide, there is no separate hmset()method; instead,hset()is used for setting multiple fields.
- For hmget(), both libraries require a key and a list of fields.
redis-py
# Set multiple fields
await r.hmset('hash', {'key1': '1', 'key2': '2'})
# Get multiple fields
values = await r.hmget('hash', ['key1', 'key2'])  # [b"1", b"2"] or ["1", "2"] if decode_responses=TrueGlide
# Set multiple fields (same as hset in Glide)
await client.hset('hash', {'key1': '1', 'key2': '2'})
# Get multiple fields
values = await client.hmget('hash', ['key1', 'key2'])  # [b"1", b"2"]HGETALL
The HGETALL command retrieves all field-value pairs from a hash.
- Both redis-py and Glide support this command in the same way.
- Returns a dictionary with field names as keys and their values.
redis-py
await r.hset('user', mapping={'name': 'John', 'age': '30'})
user = await r.hgetall('user')  # {b'name': b'John', b'age': b'30'} or {'name': 'John', 'age': '30'} if decode_responses=TrueGlide
await client.hset('user', {'name': 'John', 'age': '30'})
user = await client.hgetall('user')  # {b'name': b'John', b'age': b'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 redis-py, hdel()accepts multiple fields as separate arguments or as a list and returns the number of fields removed.
- In Glide, hdel()requires a list of fields.
- For hexists(), both libraries return True if the field exists, False if it doesn't.
redis-py
await r.hset('hash', mapping={'key1': '1', 'key2': '2', 'key3': '3'})
await r.hdel('hash', 'key1', 'key2')  # 2 (fields deleted)
# or
await r.hdel('hash', ['key1', 'key2'])  # 2 (fields deleted)
exists = await r.hexists('hash', 'key3')  # True (exists)
not_exists = await r.hexists('hash', 'key1')  # False (doesn't exist)Glide
await client.hset('hash', {'key1': '1', 'key2': '2', 'key3': '3'})
await client.hdel('hash', ['key1', 'key2'])  # 2 (fields deleted)
exists = await client.hexists('hash', 'key3')  # True
not_exists = await client.hexists('hash', 'key1')  # FalseLPUSH & RPUSH
The LPUSH command adds elements to the beginning of a list, while RPUSH adds elements to the end of a list.
- In redis-py, these commands accept multiple elements as separate arguments or as a list.
- In Glide, they require a list of elements.
- Both return the length of the list after the operation.
redis-py
length_of_list = await r.lpush('list', 'a', 'b', 'c')  # length_of_list = 3
# or
length_of_list = await r.lpush('list', ['a', 'b', 'c'])  # length_of_list = 3
length_of_list = await r.rpush('list', 'd', 'e')  # length_of_list = 5
# or
length_of_list = await r.rpush('list', ['d', 'e'])  # length_of_list = 5Glide
length_of_list = await client.lpush('list', ['a', 'b', 'c'])  # length_of_list = 3
length_of_list = await client.rpush('list', ['d', 'e'])  # length_of_list = 5LPOP & RPOP
The LPOP command removes and returns the first element of a list, while RPOP removes and returns the last element.
- Both redis-py and Glide support these commands in the same way.
- Returns None if the list doesn't exist or is empty.
redis-py
await r.rpush('list', ['a', 'b', 'c'])
first = await r.lpop('list')  # b"a" or "a" if decode_responses=True
last = await r.rpop('list')  # b"c" or "c" if decode_responses=TrueGlide
await client.rpush('list', ['a', 'b', 'c'])
first = await client.lpop('list')  # b"a"
last = await client.rpop('list')  # b"c"LRANGE
The LRANGE command retrieves a range of elements from a list.
- Both redis-py and Glide support this command in the same way.
- The range is specified by start and stop indices, where 0 is the first element, -1 is the last element.
redis-py
await r.rpush('list', ['a', 'b', 'c', 'd', 'e'])
elements = await r.lrange('list', 0, 2)  # [b"a", b"b", b"c"] or ["a", "b", "c"] if decode_responses=TrueGlide
await client.rpush('list', ['a', 'b', 'c', 'd', 'e'])
elements = await client.lrange('list', 0, 2)  # [b"a", b"b", b"c"]SADD & SMEMBERS
The SADD command adds one or more members to a set, while SMEMBERS returns all members of a set.
- In redis-py, sadd()accepts multiple members as separate arguments or as a list.
- In Glide, sadd()requires a list of members.
- Both return the number of members that were added to the set (excluding members that were already present).
redis-py
await r.sadd('set', 'a', 'b', 'c')  # 3 (members added)
# or
await r.sadd('set', ['a', 'b', 'c'])  # 3 (members added)
members = await r.smembers('set')  # {b"a", b"b", b"c"} or {"a", "b", "c"} if decode_responses=TrueGlide
await client.sadd('set', ['a', 'b', 'c'])  # 3 (members added)
members = await client.smembers('set')  # {b"a", b"b", b"c"}SREM & SISMEMBER
The SREM command removes one or more members from a set, while SISMEMBER checks if a value is a member of a set.
- In redis-py, srem()accepts multiple members as separate arguments or as a list and returns the number of members removed.
- In Glide, srem()requires a list of members.
- For sismember(), both libraries return True if the member exists, False if it doesn't.
redis-py
await r.sadd('set', ['a', 'b', 'c'])
await r.srem('set', 'a', 'b')  # 2 (members removed)
# or
await r.srem('set', ['a', 'b'])  # 2 (members removed)
is_member = await r.sismember('set', 'c')  # True (is member)
not_member = await r.sismember('set', 'a')  # False (not member)Glide
await client.sadd('set', ['a', 'b', 'c'])
await client.srem('set', ['a', 'b'])  # 2 (members removed)
is_member = await client.sismember('set', 'c')  # True
not_member = await client.sismember('set', 'a')  # FalseZADD & ZRANGE
The ZADD command adds one or more members with scores to a sorted set, while ZRANGE retrieves members from a sorted set by index range.
- In redis-py, zadd()accepts score-member pairs as separate arguments or as a mapping.
- In Glide, zadd()requires a list of objects with score and member properties.
- For zrange()with scores, redis-py uses a 'withscores' parameter, while Glide uses an options object.
redis-py
# Using separate arguments
await r.zadd('sortedSet', {'one': 1, 'two': 2, 'three': 3})  # 3 (members added)
members = await r.zrange('sortedSet', 0, -1)  # [b"one", b"two", b"three"] or ["one", "two", "three"] if decode_responses=True
# With scores
with_scores = await r.zrange('sortedSet', 0, -1, withscores=True)
# [(b"one", 1.0), (b"two", 2.0), (b"three", 3.0)] or [("one", 1.0), ("two", 2.0), ("three", 3.0)] if decode_responses=TrueGlide
await client.zadd('sortedSet', [
  {'score': 1, 'member': 'one'},
  {'score': 2, 'member': 'two'},
  {'score': 3, 'member': 'three'}
])  # 3 (members added)
members = await client.zrange('sortedSet', 0, -1)  # [b"one", b"two", b"three"]
# With scores
with_scores = await client.zrange('sortedSet', 0, -1, with_scores=True)
# [(b"one", 1.0), (b"two", 2.0), (b"three", 3.0)]ZREM & ZSCORE
The ZREM command removes one or more members from a sorted set, while ZSCORE returns the score of a member in a sorted set.
- In redis-py, zrem()accepts multiple members as separate arguments or as a list.
- In Glide, zrem()requires a list of members.
- Both return the number of members that were removed from the sorted set.
redis-py
await r.zadd('sortedSet', {'one': 1, 'two': 2, 'three': 3})
await r.zrem('sortedSet', 'one', 'two')  # 2 (members removed)
# or
await r.zrem('sortedSet', ['one', 'two'])  # 2 (members removed)
score = await r.zscore('sortedSet', 'three')  # 3.0Glide
await client.zadd('sortedSet', [
  {'score': 1, 'member': 'one'},
  {'score': 2, 'member': 'two'},
  {'score': 3, 'member': 'three'}
])
await client.zrem('sortedSet', ['one', 'two'])  # 2 (members removed)
score = await client.zscore('sortedSet', 'three')  # 3.0ZRANK & ZREVRANK
The ZRANK command returns the rank (position) of a member in a sorted set, while ZREVRANK returns the rank in reverse order.
- Both redis-py and Glide support these commands in the same way.
- Ranks are 0-based, meaning the member with the lowest score has rank 0.
- 
ZREVRANKreturns the rank in descending order, where the member with the highest score has rank 0.
redis-py
await r.zadd('sortedSet', {'one': 1, 'two': 2, 'three': 3})
rank = await r.zrank('sortedSet', 'two')  # 1 (0-based index)
rev_rank = await r.zrevrank('sortedSet', 'two')  # 1 (0-based index from end)Glide
await client.zadd('sortedSet', [
  {'score': 1, 'member': 'one'},
  {'score': 2, 'member': 'two'},
  {'score': 3, 'member': 'three'}
])
rank = await client.zrank('sortedSet', 'two')  # 1 (0-based index)
rev_rank = await client.zrevrank('sortedSet', 'two')  # 1 (0-based index from end)Transactions (MULTI / EXEC)
The MULTI command starts a transaction block, while EXEC executes all commands issued after MULTI.
- In redis-py, transactions are created using r.pipeline(transaction=True)and executed withexecute().
- In Glide, transactions are created using the Transactionclass and executed withclient.exec().
- The result format is similar: both return a list of results corresponding to each command in the transaction.
redis-py
# Create a transaction
pipeline = r.pipeline(transaction=True)
pipeline.set("key", "value")
pipeline.get("key")
result = await pipeline.execute()  # [True, b"value"] or [True, "value"] if decode_responses=TrueGlide
from glide import Transaction
# Create a transaction
transaction = Transaction()
transaction.set("key", "value")
transaction.get("key")
result = await client.exec(transaction)  # ["OK", b"value"]EVAL / EVALSHA
The EVAL command executes a Lua script on the server, while EVALSHA executes a script cached on the server using its SHA1 hash.
- In redis-py, these commands require specifying the script, the number of keys, and passing keys and arguments separately.
- In Glide, scripts are created using the Scriptclass and executed withinvoke_script(), with keys and arguments passed in separate lists.
- 
Glide automatically handles script caching, so there's no need for separate EVALSHAhandling.
redis-py
# EVAL
lua_script = "return {KEYS[1], ARGV[1]}"
result = await r.eval(lua_script, 1, "foo", "bar")
print(result)  # [b'foo', b'bar'] or ['foo', 'bar'] if decode_responses=True
# EVALSHA
sha = await r.script_load(lua_script)
sha_result = await r.evalsha(sha, 1, "foo", "bar")
print(sha_result)  # [b'foo', b'bar'] or ['foo', 'bar'] if decode_responses=TrueGlide
from glide import Script
lua_script = Script("return {KEYS[1], ARGV[1]}")
result = await client.invoke_script(lua_script, keys=["foo"], args=["bar"])
print(result)  # [b'foo', b'bar']AUTH
The AUTH command authenticates a client connection to the Valkey server.
- In redis-py, authentication is done using the auth()method or during client initialization.
- In Glide, authentication is handled during client initialization using ServerCredentials.
redis-py
# During initialization
r = redis.Redis(host='localhost', port=6379, password='mypass')
# Or after initialization
await r.auth('mypass')  # TrueGlide
# During initialization
credentials = ServerCredentials(password="mypass")
client_config = GlideClientConfiguration(
    addresses=[NodeAddress(host="localhost", port=6379)],
    credentials=credentials
)
client = await GlideClient.create(client_config)Custom Commands
Both libraries provide ways to execute custom or raw Redis commands.
- In redis-py, you can use the execute_command()method.
- In Glide, you can use the custom_command()method.
redis-py
# Execute a raw command
result = await r.execute_command('SET', 'key', 'value')
print(result)  # True or "OK" depending on the command
# Another example
result = await r.execute_command('HSET', 'hash', 'field', 'value')
print(result)  # 1Glide
# Execute a raw command
result = await client.custom_command(['SET', 'key', 'value'])
print(result)  # "OK"
# Another example
result = await client.custom_command(['HSET', 'hash', 'field', 'value'])
print(result)  # 1Close / Disconnect
Properly closing connections is important to free up resources and avoid connection leaks.
- Both redis-py and Glide provide simple close()methods to close connections.
- In redis-py, you can also use connection pools which handle connection lifecycle automatically.
redis-py
# Close connection
await r.close()
# For cluster connections
await rc.close()
# Connection pools are closed automatically when the client is closedGlide
# Close client (works for both standalone and cluster)
await client.close()Below is a comprehensive chart comparing common Redis commands between redis-py and Valkey Glide:
| Command | redis-py | Valkey Glide | 
|---|---|---|
| Connection | ||
| Connect | redis.Redis(host='localhost', port=6379) | GlideClient.create(GlideClientConfiguration(addresses=[NodeAddress(host="localhost", port=6379)])) | 
| Cluster | RedisCluster(startup_nodes=[{"host": "127.0.0.1", "port": 6379}]) | GlideClusterClient.create(GlideClusterClientConfiguration(addresses=[NodeAddress(host="127.0.0.1", port=6379)])) | 
| Auth | r.auth('pass') | Set in configuration with ServerCredentials | 
| Select DB | r.select(1) | client.select(1) | 
| Strings | ||
| SET | r.set('key', 'val') | client.set('key', 'val') | 
| GET | r.get('key') | client.get('key') | 
| SETEX | r.setex('key', 10, 'val') | client.set('key', 'val', expiry=ExpirySet(ExpiryType.SEC, 10)) | 
| SETNX | r.setnx('key', 'val') | client.set('key', 'val', conditional_set=ConditionalChange.ONLY_IF_DOES_NOT_EXIST) | 
| MSET | r.mset({'key1': 'val1'}) | client.mset({'key1': 'val1'}) | 
| MGET | r.mget(['key1', 'key2']) | client.mget(['key1', 'key2']) | 
| INCR | r.incr('counter') | client.incr('counter') | 
| DECR | r.decr('counter') | client.decr('counter') | 
| INCRBY | r.incrby('counter', 5) | client.incrby('counter', 5) | 
| DECRBY | r.decrby('counter', 5) | client.decrby('counter', 5) | 
| APPEND | r.append('key', 'val') | client.append('key', 'val') | 
| GETRANGE | r.getrange('key', 0, 3) | client.getrange('key', 0, 3) | 
| SETRANGE | r.setrange('key', 0, 'val') | client.setrange('key', 0, 'val') | 
| Keys | ||
| DEL | r.delete('key1', 'key2')orr.delete(['key1', 'key2']) | client.delete(['key1', 'key2']) | 
| EXISTS | r.exists('key1', 'key2')orr.exists(['key1', 'key2']) | client.exists(['key1', 'key2']) | 
| EXPIRE | r.expire('key', 10) | client.expire('key', 10) | 
| TTL | r.ttl('key') | client.ttl('key') | 
| KEYS | r.keys('pattern') | client.keys('pattern') | 
| SCAN | r.scan(cursor=0, match='*') | client.scan('0') | 
| RENAME | r.rename('old', 'new') | client.rename('old', 'new') | 
| RENAMENX | r.renamenx('old', 'new') | client.renamenx('old', 'new') | 
| Hashes | ||
| HSET | r.hset('hash', 'k1', 'v1')orr.hset('hash', mapping={'k1': 'v1'}) | client.hset('hash', {'k1': 'v1'}) | 
| HGET | r.hget('hash', 'field') | client.hget('hash', 'field') | 
| HMSET | r.hmset('hash', {'k1': 'v1'}) | client.hset('hash', {'k1': 'v1'}) | 
| HMGET | r.hmget('hash', ['k1', 'k2']) | client.hmget('hash', ['k1', 'k2']) | 
| HGETALL | r.hgetall('hash') | client.hgetall('hash') | 
| HDEL | r.hdel('hash', 'k1', 'k2')orr.hdel('hash', ['k1', 'k2']) | client.hdel('hash', ['k1', 'k2']) | 
| HEXISTS | r.hexists('hash', 'field') | client.hexists('hash', 'field') | 
| Lists | ||
| LPUSH | r.lpush('list', 'a', 'b')orr.lpush('list', ['a', 'b']) | client.lpush('list', ['a', 'b']) | 
| RPUSH | r.rpush('list', 'a', 'b')orr.rpush('list', ['a', 'b']) | client.rpush('list', ['a', 'b']) | 
| LPOP | r.lpop('list') | client.lpop('list') | 
| RPOP | r.rpop('list') | client.rpop('list') | 
| LRANGE | r.lrange('list', 0, -1) | client.lrange('list', 0, -1) | 
| Sets | ||
| SADD | r.sadd('set', 'a', 'b')orr.sadd('set', ['a', 'b']) | client.sadd('set', ['a', 'b']) | 
| SMEMBERS | r.smembers('set') | client.smembers('set') | 
| SREM | r.srem('set', 'a', 'b')orr.srem('set', ['a', 'b']) | client.srem('set', ['a', 'b']) | 
| SISMEMBER | r.sismember('set', 'a') | client.sismember('set', 'a') | 
| Sorted Sets | ||
| ZADD | r.zadd('zset', {'a': 1, 'b': 2}) | client.zadd('zset', [{'score': 1, 'member': 'a'}, {'score': 2, 'member': 'b'}]) | 
| ZRANGE | r.zrange('zset', 0, -1) | client.zrange('zset', 0, -1) | 
| ZRANGE with scores | r.zrange('zset', 0, -1, withscores=True) | client.zrange('zset', 0, -1, with_scores=True) | 
| ZREM | r.zrem('zset', 'a', 'b')orr.zrem('zset', ['a', 'b']) | client.zrem('zset', ['a', 'b']) | 
| ZSCORE | r.zscore('zset', 'a') | client.zscore('zset', 'a') | 
| ZRANK | r.zrank('zset', 'a') | client.zrank('zset', 'a') | 
| ZREVRANK | r.zrevrank('zset', 'a') | client.zrevrank('zset', 'a') | 
| Transactions | ||
| MULTI/EXEC | r.pipeline(transaction=True).set('k', 'v').get('k').execute() | client.exec(Transaction().set('k', 'v').get('k')) | 
| Lua Scripts | ||
| EVAL | r.eval(script, 1, 'key', 'arg') | client.invoke_script(Script(script), keys=['key'], args=['arg']) | 
| EVALSHA | r.evalsha(sha, 1, 'key', 'arg') | client.invoke_script(Script(script), keys=['key'], args=['arg']) | 
| Custom Commands | ||
| Raw Command | r.execute_command('SET', 'key', 'value') | client.custom_command(['SET', 'key', 'value']) | 
| Connection Management | ||
| Close | r.close() | client.close() |