Chapter 04 · Hashes and Object-Like Records

Field-Level Expiration Capabilities Where Available and Version-Aware Client Design

Use Redis 7.4+ hash-field expiration and Redis 8.0+ HGETEX/HSETEX deliberately, verify server/client capability, and distinguish field TTL from key TTL and cache policy.

Intermediate → Advanced130–165 minutesField-expiration + client capability labRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart stores a customer session profile in one hash. Stable fields such as customer_id and locale should persist with the record, while fields such as otp_verified, shipping_quote, and a temporary recommendation token should expire independently. Redis 7.4 introduced hash-field expiration, and Redis 8.0 added convenience commands that combine hash reads/writes with field expiration. These features are powerful precisely because they are version-sensitive and have different mutation rules from key-level TTL.

01

Verify server command availability before using field-expiration features and distinguish Redis 7.4 versus 8.0 command additions.

02

Use HEXPIRE/HPEXPIRE, HTTL/HPTTL, HPERSIST, and conditional NX/XX/GT/LT semantics with correct per-field return codes.

03

Use Redis 8.0+ HGETEX/HSETEX deliberately and explain how HSET overwrite, numeric mutation, KEEPTTL, and key TTL interact with field TTL.

04

Design clients that capability-check server and library support rather than assuming a wrapper method exists because a server version string looks new enough.

05

Connect field expiration to Search visibility, persistence/replication, ACL/TLS, failover, privacy, and cache-freshness policy without treating TTL as exact scheduling.

Exact lab baseline

All Chapter 04 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from Docker Official Image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, host publication 127.0.0.1:6379, TLS disabled only because traffic stays on loopback, default ACL user disabled, named ACL users atlasmart-app and academy-admin, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data volume, and no explicit Redis maxmemory limit or eviction policy. The application ACL is restricted to ~atlasmart:* and normal read/write/connection categories. The primary interface is the redis-cli shipped in the same 8.10.1 image, so server and CLI versions stay aligned. The mandatory path uses redis-cli only. An optional redis-py 8.0.1 snippet demonstrates client capability checks; no Python package is required to complete the chapter.

1. Prove the feature surface before relying on it

Field expiration is not a timeless Redis assumption. HEXPIRE, HPEXPIRE, HTTL, HPTTL, and HPERSIST are available from Redis 7.4. Redis 8.0 adds HGETEX, HSETEX, and HGETDEL. A robust client can ask the server for command metadata rather than merely parse a marketing/product label.

redis-cli · capability evidence card
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO serverdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO HEXPIRE HPEXPIRE HTTL HPTTL HPERSIST HGETEX HSETEX HGETDEL# On the pinned Redis Open Source 8.10.1 lab these commands should be present.# On an older/proxy/compatible service, missing command metadata is a compatibility signal.

Managed services and Redis-compatible proxies can expose a subset or altered rollout schedule. Application startup should fail safely or choose a tested fallback when a required command is unavailable.

2. HEXPIRE/HTTL: expiration belongs to individual fields

HEXPIRE key seconds FIELDS n field... applies relative TTLs to selected fields. HPEXPIRE uses milliseconds. For each requested field, HEXPIRE/HPEXPIRE return -2 when the key/field is missing, 0 when an NX/XX/GT/LT condition rejects the update, 1 when expiration is set or updated, and 2 when an immediate/past expiration deletes the field. HTTL/HPTTL separately return a positive remaining TTL, -1 for an existing persistent field, or -2 when the key/field is missing. Expiration is not an exact scheduler; field deletion becomes observable according to Redis expiration processing and access behavior, not a promise of execution at an exact millisecond.

redis-cli · set and inspect independent field lifetimes
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch04:session:42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:session:42 customer_id 42 locale en otp_verified 1 shipping_quote 12.50docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 30 FIELDS 1 otp_verifieddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HPEXPIRE atlasmart:ch04:session:42 45000 FIELDS 1 shipping_quotedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 3 customer_id otp_verified missingdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HPTTL atlasmart:ch04:session:42 FIELDS 1 shipping_quote# Expected shapes: customer_id -> -1; otp_verified -> positive; missing -> -2; quote -> positive ms.docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HPERSIST atlasmart:ch04:session:42 FIELDS 2 otp_verified customer_iddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 2 otp_verified customer_id# HPERSIST returns 1 when it removes a field TTL and -1 when the field was already persistent.

HPERSIST removes a field expiration without changing the value. Its per-field result is 1 when an expiration was removed, -1 when an existing field was already persistent, and -2 for a missing key/field. The following HTTL should therefore report -1 for both surviving fields.

3. Conditional field expiry: NX, XX, GT, and LT

The conditional modes mirror lifecycle intent rather than value comparison. NX sets expiration only when the field has no expiration. XX requires an existing expiration. GT accepts a new expiration only when it is greater than the current one, and LT only when it is less. These conditions operate per field and return a result for each requested field.

redis-cli · make expiry policy conditions observable
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:session:42 promo_banner springdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 120 NX FIELDS 1 promo_bannerdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 60 NX FIELDS 1 promo_bannerdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 180 GT FIELDS 1 promo_bannerdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 300 LT FIELDS 1 promo_bannerdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 1 promo_banner# Read each integer result; do not treat a rejected condition as a transport error.

A client that discards per-field return codes can falsely report that all requested expirations were applied.

4. HSET clears field TTL; increments preserve it

The mutation rule is precise: commands that delete or overwrite a hash field's contents, including HDEL and ordinary HSET, clear that field's expiration. Operations that conceptually modify the value without replacing the field, such as HINCRBY, leave the field TTL intact. The hash key's own key-level TTL is a separate property and is not the same timer.

redis-cli · contrast overwrite with numeric mutation
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:session:42 refresh_count 0 temporary_note originaldocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 120 FIELDS 2 refresh_count temporary_notedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HINCRBY atlasmart:ch04:session:42 refresh_count 1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:session:42 temporary_note replaceddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 2 refresh_count temporary_note# refresh_count -> positive TTL; temporary_note -> -1 after HSET overwrite.

This difference should be tested in application code because “any write refreshes TTL” and “any write clears TTL” are both incorrect generalizations.

5. Redis 8.0+: HSETEX and HGETEX combine data access with expiry policy

HSETEX sets one or more fields and can assign EX/PX/EXAT/PXAT expiration, preserve existing field TTL with KEEPTTL, or condition the multi-field set with FNX/FXX. HGETEX retrieves fields and can set a new expiration or make them persistent. These commands reduce round trips and race windows, but their exact option semantics are the contract—not a generic “sliding session” guarantee.

redis-cli · HSETEX and HGETEX on the pinned 8.10.1 server
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSETEX atlasmart:ch04:session:42 EX 90 FIELDS 2 shipping_quote 13.25 recommendation_token rec-abcdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 2 shipping_quote recommendation_tokendocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSETEX atlasmart:ch04:session:42 FXX KEEPTTL FIELDS 1 shipping_quote 13.50docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 1 shipping_quotedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HGETEX atlasmart:ch04:session:42 EX 30 FIELDS 1 recommendation_tokendocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 1 recommendation_tokendocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HGETEX atlasmart:ch04:session:42 PERSIST FIELDS 1 recommendation_tokendocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 1 recommendation_token# HGETEX PERSIST returns the field value and removes that field TTL; HTTL should then be -1.

If a library does not yet expose a typed helper, do not silently emulate the operation with separate read/write/expire commands and claim identical atomicity. Either use a tested raw-command escape hatch against a capability-checked server or choose an explicit fallback with documented weaker semantics.

6. Version-aware client design: capability first, wrapper second

As of this course snapshot, redis-py 8.0.1 is a current release and Redis documentation exposes Python APIs for modern hash-expiration commands. Client releases can change response protocol defaults, method names, type annotations, and Cluster routing behavior independently of the server. Record both versions in diagnostics.

python · optional redis-py 8.0.1 capability gate
# pip install redis==8.0.1import redisr = redis.Redis(host="127.0.0.1", port=6379, db=0,                username="atlasmart-app",                password="AtlasMart-App-Lab-Only-2026",                decode_responses=True)info = r.info("server")cmds = r.execute_command("COMMAND", "INFO", "HEXPIRE", "HTTL", "HSETEX", "HGETEX")print("server:", info.get("redis_version"))print("client:", redis.__version__)print("commands available:", [c is not None for c in cmds])# Only after capability passes should application code depend on these semantics.# Keep an integration test against the exact managed/proxy target as well.

For production, capability negotiation should be deterministic at startup/deployment rather than discovering a missing command in the middle of a customer request.

7. Expiration signals are not business-state logs

Field expiry affects authoritative Redis state; notification mechanisms are signals, not durable audit logs. If privacy policy says an OTP field must not be usable after a deadline, the application should read authoritative state and treat missing/expired data correctly. If compliance requires proof of deletion or retention, build auditable workflows beyond a best-effort notification subscriber.

Redis Search in Redis 8 has explicit behavior for expiring hash fields. Index/query visibility can therefore depend on expiration semantics and query timing; Chapter 09 measures that behavior. Do not assume a secondary index makes expired fields immortal or that a notification is a transactional record of every expiry.

redis-cli · observe lifecycle without relying on notification timing
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:session:42 one_time 1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:session:42 2 FIELDS 1 one_timedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 1 one_time# Wait >2 seconds on your machine, then read authoritative state:docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HGET atlasmart:ch04:session:42 one_timedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:session:42 FIELDS 1 one_time# Expect the field eventually to be absent; do not promise an exact deletion millisecond.

8. Hands-on lab: mixed-lifetime session record

Create a stable session hash with one permanent identity field, one 60-second quote, one 30-second token, and one counter whose TTL survives HINCRBY. Verify server capabilities first. Then overwrite one expiring field with HSET to demonstrate TTL clearing and repair it with HSETEX.

redis-cli · field-expiration acceptance lab
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch04:lab:sessiondocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO HEXPIRE HTTL HSETEX HGETEXdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:lab:session customer_id 42 quote 12.00 token tok-1 refresh_count 0docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:lab:session 60 FIELDS 1 quotedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:lab:session 30 FIELDS 1 tokendocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HEXPIRE atlasmart:ch04:lab:session 120 FIELDS 1 refresh_countdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HINCRBY atlasmart:ch04:lab:session refresh_count 1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSET atlasmart:ch04:lab:session quote 12.50docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:lab:session FIELDS 4 customer_id quote token refresh_countdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HSETEX atlasmart:ch04:lab:session EX 60 FIELDS 1 quote 12.50docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app HTTL atlasmart:ch04:lab:session FIELDS 1 quote

Verification checklist:

  • COMMAND INFO proves the required commands exist on the actual server before the lab depends on them.
  • customer_id reports -1 field TTL, while token/refresh_count/quote report positive TTLs at the relevant steps.
  • HINCRBY preserves refresh_count TTL; HSET clears quote field TTL; HSETEX restores quote with an explicit TTL.
  • The lab distinguishes field TTL from any key-level TTL and does not treat expiry as exact scheduling.
  • Client/version assumptions are recorded; managed/proxy targets require their own integration test.
redis-cli · cleanup Lesson 4 fixtures
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app UNLINK atlasmart:ch04:lab:session atlasmart:ch04:session:42

9. Production judgment

Field TTL is appropriate when one flat hash record contains values with legitimately different lifetimes and the feature is supported/tested across your exact server, client, persistence, replication, and managed-service topology. It can reduce many-key cardinality while retaining per-field lifecycle control. It also increases lifecycle complexity: every mutation path must know whether it clears, preserves, shortens, extends, or removes the field TTL.

Monitor command errors, expired-field rates where exposed, hash cardinality, memory, stale-value incidents, and client capability mismatches. Test failover and restore behavior before relying on expiration for correctness-sensitive workflows. TTL is not encryption, authorization, or proof of deletion; ACL/TLS/network boundaries and application authorization remain separate controls.

10. Summary and next step

Redis 7.4 introduced field-level expiration and Redis 8.0 added HGETEX/HSETEX/HGETDEL convenience commands. TTL is per field, return codes are per field, HSET overwrite clears field expiry, numeric mutation preserves it, and key TTL remains a separate lifecycle layer. Capability-check the server and client instead of assuming version parity. Next, you will decide when this flat hash model is preferable to Redis JSON or many independent keys.

Check your understanding

  1. What does HTTL return for an existing field without field expiration?
  2. What does HTTL return for a missing field or missing hash key?
  3. What happens to a field TTL when ordinary HSET overwrites that field?
  4. Why is HSETEX different from HSET followed by HEXPIRE?
  5. Why should an application call COMMAND INFO during compatibility checks?
Review the answers

1. -1.

2. -2 for that requested field.

3. The field expiration is cleared.

4. HSETEX combines value setting and expiration policy in one command with its documented atomic command semantics, avoiding the inter-command race/window.

5. It verifies the actual target exposes required commands; server/client/product labels alone may not prove feature availability on proxies or managed services.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.