This episode covers how to run complex logic atomically on the Redis server: EVAL and EVALSHA for Lua scripting with conditional logic, and Redis Functions in Redis 7 which register functions permanently to be called with FCALL.

MULTI/EXEC in episode 9 can only run a series of commands without logic. But what if you need decisions inside a batch — for example "decrease stock only if the stock is still sufficient, then record the order"? Episode 10 answers this with Lua scripting and Redis Functions.
Lua scripting moves application logic into the Redis server, executed atomically without interruption. Redis Functions (Redis 7+) perfects this with permanent registration on the server. This is one of the capabilities that makes Redis so powerful for rate limiting, distributed locks, and high-precision counters.
Lua was chosen because it's lightweight, fast, and easy to embed. When a Lua script runs, the entire script executes atomically — no other command can interrupt mid-way, like MULTI/EXEC but with conditional logic, variables, and loops. This is impossible with ordinary transactions.
redis-cli EVAL "return redis.call('GET', KEYS[1])" 1 user:1:nameredis-cli EVAL "return redis.call('GET', KEYS[1])" 1 user:1:name executes a Lua script that calls GET. Inside the script, redis.call() runs a Redis command, KEYS[1] takes the first key, and ARGV[1] takes a non-key argument.
This is the main strength — decision logic inside the server:
local stok = tonumber(redis.call('GET', KEYS[1]))
if not stok or stok < tonumber(ARGV[1]) then
return -1
end
redis.call('DECRBY', KEYS[1], ARGV[1])
return 1The script above reads the stock, checks sufficiency, and only decreases if safe — all atomically. Call it via EVAL:
redis-cli EVAL "local s = tonumber(redis.call('GET', KEYS[1])); if not s or s < tonumber(ARGV[1]) then return -1 end; redis.call('DECRBY', KEYS[1], ARGV[1]); return 1" 1 stock:sku-1 2The script returns 1 on success, -1 if the stock is insufficient — a business decision result straight from the server, without needing a lock on the application side.
Sending the full script every time is wasteful. EVALSHA uses the SHA1 hash of a script that was already sent once:
redis-cli SCRIPT LOAD "return 1"
redis-cli EVALSHA <sha1_hasil_load> 0SCRIPT LOAD stores the script and returns its hash, then EVALSHA calls the script via the hash — saving bandwidth. Client pattern: SCRIPT LOAD once, then EVALSHA repeatedly; if the hash is unknown (NOSCRIPT error), fall back to EVAL.
Danger
Long, expensive Lua scripts will block the entire server while executing — just like any other slow command. Keep scripts short, and use SCRIPT KILL only if the execution hasn't written anything.
Redis 7 introduced Redis Functions: registering functions permanently on the server. The difference from EVAL: the script is registered once (FUNCTION LOAD), then called any time with FCALL without resending the script or managing hashes. Functions also have clear names and organized libraries.
#!lua name=mylib
redis.register_function('increment', function(keys, args)
return redis.call('INCRBY', keys[1], args[1])
end)The line #!lua name=mylib declares a library named mylib, then redis.register_function registers the increment function that can be called at any time.
redis-cli -x FUNCTION LOAD < script.lua
redis-cli FCALL mylib.increment 1 counter 5FUNCTION LOAD < script.lua registers the script to the server (the -x option reads from stdin). Once registered, FCALL mylib.increment 1 counter 5 calls the function whenever needed — without resending the script, and the function persists even when new clients connect.
| Aspect | EVAL/EVALSHA | Redis Functions |
|---|---|---|
| Registration | Per client, via hash | Permanent on the server |
| Invocation | EVALSHA + hash | FCALL + function name |
| Management | Manual, per application | Centralized, organized per library |
| Best for | One-off scripts | Reusable business logic |
For production, prefer Redis Functions: scripts are defined once, easy to version, and don't depend on each client's state.
Episode 10 equipped you with Lua scripting and Redis Functions: EVAL for atomic execution with conditional logic, EVALSHA to save bandwidth via hashes, and FUNCTION LOAD/FCALL to register permanent functions in Redis 7.
Key takeaways:
redis.call() runs Redis commands from inside a script.EVALSHA saves bandwidth by using the script hash.FCALL calls a function without resending the script.In the next episode, episode 11, we cover Caching Strategies & Design Patterns — how Redis is used in the real world. You'll learn Cache-Aside, Write-Through, and Write-Behind, the allkeys-lru and allkeys-lfu eviction policies, rate limiting with Sorted Sets, Redlock-style distributed locks, and the session store pattern. Let's continue!