Scripts turn read-decide-write sequences into one atomic, single-round-trip operation.
EVAL script numkeys key... arg... runs a Lua script on the server. Inside, KEYS[1] and ARGV[1] hold the inputs and redis.call("GET", KEYS[1]) runs commands (redis.pcall returns errors instead of raising). The whole script is atomic: no other command runs while it executes, so it can read, decide and write without races or WATCH retries.
Rules that matter:
- pass every key the script touches in
KEYS, never build key names inside; Redis Cluster uses them to route the script, and all keys must be in the same hash slot, - keep scripts short: a long-running script blocks the whole server (
busy-reply-threshold, default 5 seconds, after which onlySCRIPT KILLorSHUTDOWN NOSAVEare accepted), - scripts should be deterministic with respect to their inputs.
SCRIPT LOAD returns a SHA1 and EVALSHA sha ... runs the cached script; clients handle the NOSCRIPT fallback for you.
Redis Functions (7.0+) are the managed successor: FUNCTION LOAD registers a library of named functions that persist with the data and replicate, and FCALL name numkeys ... calls one. Prefer functions for logic that is part of your application's API.
A classic use is a safe lock release: delete the lock only if it still holds your token, which a plain GET then DEL from the client cannot do atomically.
Example
# release a lock only if we still own it (atomic compare-and-delete)
redis-cli SET lock:report tok-123 NX EX 30 # OK
redis-cli EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1]) else return 0 end" 1 lock:report tok-999
# (integer) 0 wrong token, lock kept
redis-cli EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1]) else return 0 end" 1 lock:report tok-123
# (integer) 1 released
# the same as a named Redis Function
redis-cli FUNCTION LOAD "#!lua name=locks
redis.register_function('unlock', function(keys, args)
if redis.call('GET', keys[1]) == args[1] then return redis.call('DEL', keys[1]) end
return 0 end)" # "locks"
redis-cli FCALL unlock 1 lock:report tok-123 # (integer) 0 already goneRemember
- Scripts run atomically on the server: read, decide, write in one step
- Pass all keys via KEYS so clusters can route them
- Long scripts block everyone; keep them fast
- Functions (7.0+) are named, persisted, replicated scripts called with FCALL
Watch out for
- Building key names inside a script from ARGV: breaks cluster routing and hides keys from Redis.