Lua Scripting
Lua scripts run atomically on the Redis server — read, branch, and write in one execution without other commands interleaving.
Introduction
Lua scripts run atomically on the Redis server — read, branch, and write in one execution without other commands interleaving. Rate limiters, safe lock release, and conditional transfers belong in Lua, not split across multiple round trips.
EVAL runs script inline; EVALSHA uses SHA1 digest after SCRIPT LOAD. Scripts should be deterministic and fast — a slow script blocks the entire event loop.
Redis 7 function libraries offer an alternative, but EVAL remains the production standard for atomic custom logic.
Understanding the topic
Key concepts
- EVAL script numkeys key [key ...] arg [arg ...].
- redis.call() — invoke commands; errors abort script.
- redis.pcall() — errors as return values.
- Scripts cached by SHA; EVALSHA on cache hit.
- Entire script atomic — no partial visibility.
- No long loops — blocks single thread.
Step-by-step explanation
- Client sends EVAL with script body and keys/args.
- Redis loads Lua interpreter if needed.
- Script executes with KEYS[] and ARGV[] arrays.
- All redis.call operations run without interruption.
- Result returned as bulk reply; script cached for EVALSHA.
Syntax reference
Common commands
- KEYS[1] — pass all key names via KEYS array for cluster slot safety.
- Keep scripts short.
- Load once with SCRIPT LOAD in deploy.
# Atomic rate limit: max 60 req/minEVAL "local c = redis.call('INCR', KEYS[1])if c == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) endreturn c" 1 rate:user:42 60
Informative example
Safe lock release — delete only if token matches:
EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] thenreturn redis.call('DEL', KEYS[1])else return 0 end" 1 lock:order:99 my-uuid-token
Never DEL lock without checking token — another process may have acquired after yours expired.
Real-world use
Real-world use cases
- Sliding window rate limiter.
- Compare-and-delete lock release.
- Conditional balance transfer with check.
- Atomic ZADD + EXPIRE + ZREMRANGEBYRANK trim.
- Idempotent claim processing with SET NX in script.
Best practices
- Pass keys in KEYS array for Cluster compatibility.
- Preload scripts; use EVALSHA in hot path.
- Version scripts in application config.
- Avoid unbounded loops and KEYS inside scripts.
- Test scripts in staging with production key patterns.
- Keep scripts under 1ms execution target.
Common mistakes
- Non-deterministic scripts (TIME, RANDOMKEY) break replication.
- Using GET+DEL in app without Lua — race on lock release.
- Huge scripts blocking event loop.
- Hardcoding keys in script body instead of KEYS array.
Advanced interview questions
Q1BeginnerWhy Lua in Redis?
Q2BeginnerEVAL vs MULTI?
Q3IntermediateSafe lock unlock?
Q4IntermediateEVALSHA benefit?
Q5AdvancedLua on Redis Cluster?
Summary
Lua = atomic custom logic on server.