HEXPIRE

HEXPIRE key seconds [NX | XX | GT | LT] FIELDS numfields field
  [field ...]
Available since:
Redis Open Source 7.4.0
Time complexity:
O(N) where N is the number of specified fields
ACL categories:
@write, @hash, @fast,
Compatibility:
Redis Software and Redis Cloud compatibility

Set an expiration (TTL or time to live) on one or more fields of a given hash key. You must specify at least one field. Field(s) will automatically be deleted from the hash key when their TTLs expire.

Field expirations will only be cleared by commands that delete or overwrite the contents of the hash fields, including HDEL and HSET commands. This means that all the operations that conceptually alter the value stored at a hash key's field without replacing it with a new one will leave the TTL untouched.

You can clear the TTL using the HPERSIST command, which turns the hash field back into a persistent field.

Note that calling HEXPIRE/HPEXPIRE with a zero TTL or HEXPIREAT/HPEXPIREAT with a time in the past will result in the hash field being deleted.

Required arguments

key

The name of the key that holds the hash.

seconds

The time to live, in seconds. Each specified field is deleted after this many seconds.

FIELDS numfields field [field ...]

The hash fields to set expiration for. numfields is the number of fields, followed by that many field names.

Optional arguments

The following options modify the command's behavior. They are mutually exclusive.

NX

For each specified field, set expiration only when the field has no expiration.

XX

For each specified field, set expiration only when the field has an existing expiration.

GT

For each specified field, set expiration only when the new expiration is greater than the current one. A non-volatile field is treated as an infinite TTL for the purposes of GT.

LT

For each specified field, set expiration only when the new expiration is less than the current one. A non-volatile field is treated as an infinite TTL for the purposes of LT.

Refreshing expires

You can call HEXPIRE using as argument a field that already has an existing TTL set. In this case, the time to live is updated to the new value.

Redis Search and field expiration

Starting with Redis 8, Redis Search has enhanced behavior when handling expiring hash fields. For detailed information about how FT.SEARCH and FT.AGGREGATE commands interact with expiring hash fields, see Key and field expiration behavior.

Examples

Field expiration: Set TTL on individual hash fields using HEXPIRE with conditional options (NX, XX, GT, LT) when you need fine-grained control over field lifecycle
HEXPIRE no-key 20 NX FIELDS 2 field1 field2
(nil)
HSET mykey field1 "hello" field2 "world"
(integer) 2
HEXPIRE mykey 10 FIELDS 3 field1 field2 field3
1) (integer) 1
2) (integer) 1
3) (integer) -2
HGETALL mykey
# Set up hash with fields
r.hset("myhash", mapping={"field1": "Hello", "field2": "World"})

# Set expiration on hash fields
res12 = r.hexpire("myhash", 10, "field1", "field2")
print(res12)  # >>> [1, 1]

# Check TTL of the fields
res13 = r.httl("myhash", "field1", "field2")
print(res13)  # >>> [10, 10] (or close to 10)

# Try to set expiration on non-existent field
res14 = r.hexpire("myhash", 10, "nonexistent")
print(res14)  # >>> [-2]

// Set up hash with fields
await client.hSet('myhash', {
  'field1': 'Hello',
  'field2': 'World'
})

// Set expiration on hash fields
const res14 = await client.hExpire('myhash', ['field1', 'field2'], 10)
console.log(res14) // [1, 1]

// Check TTL of the fields
const res15 = await client.hTTL('myhash', ['field1', 'field2'])
console.log(res15) // [10, 10] (or close to 10)

// Try to set expiration on non-existent field
const res16 = await client.hExpire('myhash', ['nonexistent'], 10)
console.log(res16) // [-2]


import assert from 'node:assert';
import { Redis } from 'ioredis';

const redis = new Redis();


await redis.hset('myhash', { field1: 'Hello', field2: 'World' });

const hmgetResult = await redis.hmget('myhash', 'field1', 'field2', 'nofield');
console.log(hmgetResult); // >>> ['Hello', 'World', null]


redis.disconnect();

        // Set up hash with fields
        Map<String, String> hExpireExampleParams = new HashMap<>();
        hExpireExampleParams.put("field1", "Hello");
        hExpireExampleParams.put("field2", "World");
        jedis.hset("myhash", hExpireExampleParams);

        // Set expiration on hash fields
        List<Long> hExpireResult1 = jedis.hexpire("myhash", 10, "field1", "field2");
        System.out.println(hExpireResult1); // >>> [1, 1]

        // Check TTL of the fields
        List<Long> hExpireResult2 = jedis.httl("myhash", "field1", "field2");
        System.out.println(hExpireResult2.size()); // >>> 2

        // Try to set expiration on non-existent field
        List<Long> hExpireResult3 = jedis.hexpire("myhash", 10, "nonexistent");
        System.out.println(hExpireResult3); // >>> [-2]
            // Set up hash with fields
            Map<String, String> hExpireExampleParams = new HashMap<>();
            hExpireExampleParams.put("field1", "Hello");
            hExpireExampleParams.put("field2", "World");

            CompletableFuture<Void> hExpireExample = asyncCommands.hset("myhash", hExpireExampleParams).thenCompose(res1 -> {
                // Set expiration on hash fields
                return asyncCommands.hexpire("myhash", 10, "field1", "field2");
            }).thenCompose(res2 -> {
                System.out.println(res2);
                // >>> [1, 1]
                // Check TTL of the fields
                return asyncCommands.httl("myhash", "field1", "field2");
            }).thenCompose(res3 -> {
                System.out.println(res3.size());
                // >>> 2
                // Try to set expiration on non-existent field
                return asyncCommands.hexpire("myhash", 10, "nonexistent");
            })
                    .thenAccept(System.out::println)
                    // >>> -2
                    .toCompletableFuture();
            // Set up hash with fields
            Map<String, String> hExpireExampleParams = new HashMap<>();
            hExpireExampleParams.put("field1", "Hello");
            hExpireExampleParams.put("field2", "World");

            Mono<Long> hExpireExample1 = reactiveCommands.hset("myhash", hExpireExampleParams).doOnNext(result -> {
            });

            hExpireExample1.block();

            // Set expiration on hash fields
            Mono<List<Long>> hExpireExample2 = reactiveCommands.hexpire("myhash", 10, "field1", "field2").collectList().doOnNext(result -> {
                System.out.println(result);
                // >>> [1, 1]
            });

            hExpireExample2.block();

            // Check TTL of the fields
            Mono<List<Long>> hExpireExample3 = reactiveCommands.httl("myhash", "field1", "field2").collectList().doOnNext(result -> {
                System.out.println(result.size());
                // >>> 2
            });

            hExpireExample3.block();

            // Try to set expiration on non-existent field
            Mono<List<Long>> hExpireExample4 = reactiveCommands.hexpire("myhash", 10, "nonexistent").collectList().doOnNext(result -> {
                System.out.println(result);
                // >>> [-2]
            });
	// Set up hash with fields
	rdb.HSet(ctx, "myhash", "field1", "Hello", "field2", "World")

	// Set expiration on hash fields
	res1, err := rdb.HExpire(ctx, "myhash", 10*time.Second, "field1", "field2").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(res1) // >>> [1 1]

	// Check TTL of the fields
	res2, err := rdb.HTTL(ctx, "myhash", "field1", "field2").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(len(res2)) // >>> 2

	// Try to set expiration on non-existent field
	res3, err := rdb.HExpire(ctx, "myhash", 10*time.Second, "nonexistent").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(res3) // >>> [-2]

	// Clean up
	rdb.Del(ctx, "myhash")

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>

int main(int argc, char **argv) {
    redisContext *c = redisConnect("127.0.0.1", 6379);

    if (c == NULL || c->err) {
        if (c) {
            printf("Connection error: %s\n", c->errstr);
            redisFree(c);
        } else {
            printf("Connection error: can't allocate redis context\n");
        }
        return 1;
    }


    redisReply *reply;

    // Set up hash with fields
    reply = redisCommand(c, "HSET %s %s %s %s %s",
        "myhash", "field1", "Hello", "field2", "World");
    freeReplyObject(reply);

    // Get multiple fields at once
    reply = redisCommand(c, "HMGET %s %s %s %s",
        "myhash", "field1", "field2", "nofield");

    printf("HMGET myhash field1 field2 nofield:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        if (reply->element[i]->type == REDIS_REPLY_NIL) {
            printf("  [%zu]: null\n", i);
        } else {
            printf("  [%zu]: %s\n", i, reply->element[i]->str);
        }
    }
    // >>> [0]: Hello
    // >>> [1]: World
    // >>> [2]: null


    freeReplyObject(reply);


    redisFree(c);

    return 0;
}

        // Set up hash with fields
        db.HashSet("myhash",
            [
                new("field1", "Hello"),
                new("field2", "World")
            ]
        );

        ExpireResult[] hexpireRes1 = db.HashFieldExpire(
            "myhash",
            new RedisValue[] { "field1", "field2" },
            TimeSpan.FromSeconds(10)
        );
        Console.WriteLine(string.Join(", ", hexpireRes1));
        // >>> Success, Success

        long[] hexpireRes2 = db.HashFieldGetTimeToLive(
            "myhash",
            new RedisValue[] { "field1", "field2" }
        );
        Console.WriteLine(string.Join(", ", hexpireRes2));
        // >>> 10, 10 (approximately)

        // Try to set expiration on non-existent field
        ExpireResult[] hexpireRes3 = db.HashFieldExpire(
            "myhash",
            new RedisValue[] { "nonexistent" },
            TimeSpan.FromSeconds(10)
        );
        Console.WriteLine(string.Join(", ", hexpireRes3));
        // >>> NoSuchField

        // Set up hash with fields
        $hExpireResult1 = $this->redis->hmset('myhash', ['field1' => 'Hello', 'field2' => 'World']);
        echo "HMSET myhash field1 Hello field2 World: " . ($hExpireResult1 ? 'OK' : 'FAIL') . "\n"; // >>> OK

        // Set expiration on hash fields
        $hExpireResult2 = $this->redis->hexpire('myhash', 10, ['field1', 'field2']);
        echo "HEXPIRE myhash 10 FIELDS field1 field2: " . json_encode($hExpireResult2) . "\n"; // >>> [1,1]

        // Check TTL of the fields
        $hExpireResult3 = $this->redis->httl('myhash', ['field1', 'field2']);
        echo "HTTL myhash FIELDS field1 field2 count: " . count($hExpireResult3) . "\n"; // >>> 2

        // Try to set expiration on non-existent field
        $hExpireResult4 = $this->redis->hexpire('myhash', 10, ['nonexistent']);
        echo "HEXPIRE myhash 10 FIELDS nonexistent: " . json_encode($hExpireResult4) . "\n"; // >>> [-2]
        // Set up hash with fields
        let hash_fields = vec![("field1", "Hello"), ("field2", "World")];
        if let Ok(res) = r.hset_multiple("myhash", &hash_fields) {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        // Set expiration on hash fields
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["field1", "field2"]) {
            Ok(res1) => {
                let res1: Vec<i32> = res1;
                println!("{:?}", res1);    // >>> [1, 1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Check TTL of the fields
        match r.httl("myhash", &["field1", "field2"]) {
            Ok(res2) => {
                let res2: Vec<i32> = res2;
                println!("{}", res2.len());    // >>> 2
            },
            Err(e) => {
                println!("Error getting TTL: {e}");
                return;
            }
        }

        // Try to set expiration on non-existent field
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["nonexistent"]) {
            Ok(res3) => {
                let res3: Vec<i32> = res3;
                println!("{:?}", res3);    // >>> [-2]
            },
            Err(e) => {
                println!("Error setting expiration on non-existent field: {e}");
                return;
            }
        }

        // Set up hash with fields
        let hash_fields = vec![("field1", "Hello"), ("field2", "World")];
        if let Ok(res) = r.hset_multiple("myhash", &hash_fields).await {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        // Set expiration on hash fields
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["field1", "field2"]).await {
            Ok(res1) => {
                let res1: Vec<i32> = res1;
                println!("{:?}", res1);    // >>> [1, 1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Check TTL of the fields
        match r.httl("myhash", &["field1", "field2"]).await {
            Ok(res2) => {
                let res2: Vec<i32> = res2;
                println!("{}", res2.len());    // >>> 2
            },
            Err(e) => {
                println!("Error getting TTL: {e}");
                return;
            }
        }

        // Try to set expiration on non-existent field
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["nonexistent"]).await {
            Ok(res3) => {
                let res3: Vec<i32> = res3;
                println!("{:?}", res3);    // >>> [-2]
            },
            Err(e) => {
                println!("Error setting expiration on non-existent field: {e}");
                return;
            }
        }

Give these commands a try in the interactive console:

HEXPIRE no-key 20 NX FIELDS 2 field1 field2 HSET mykey field1 "hello" field2 "world" HEXPIRE mykey 10 FIELDS 3 field1 field2 field3 HGETALL mykey

Redis Software and Redis Cloud compatibility

Redis
Software
Redis
Cloud
Notes
✅ Standard
✅ Active-Active
✅ Standard
✅ Active-Active

Return information

One of the following:

  • Array reply. For each field:
    • Integer reply: -2 if no such field exists in the provided hash key, or the provided key does not exist.
    • Integer reply: 0 if the specified NX | XX | GT | LT condition has not been met.
    • Integer reply: 1 if the expiration time was set/updated.
    • Integer reply: 2 when HEXPIRE/HPEXPIRE is called with 0 seconds/milliseconds or when HEXPIREAT/HPEXPIREAT is called with a past Unix time in seconds/milliseconds.
  • Simple error reply:
    • if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    • if the provided key exists but is not a hash.
RATE THIS PAGE
Back to top ↑