Redis Tutorial 0/42 lessons ~6 min read Lesson 18

    Lua Scripting

    Lua scripts run atomically on the Redis server — read, branch, and write in one execution without other commands interleaving.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    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

    1. Client sends EVAL with script body and keys/args.
    2. Redis loads Lua interpreter if needed.
    3. Script executes with KEYS[] and ARGV[] arrays.
    4. All redis.call operations run without interruption.
    5. 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.
    bash
    # Atomic rate limit: max 60 req/min
    EVAL "
    local c = redis.call('INCR', KEYS[1])
    if c == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end
    return c
    " 1 rate:user:42 60

    Informative example

    Safe lock release — delete only if token matches:

    bash
    EVAL "
    if redis.call('GET', KEYS[1]) == ARGV[1] then
    return 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

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    5 questions
    1BeginnerQuestionWhy Lua in Redis?+

    Answer

    Atomic read-modify-write with branching on server.
    2BeginnerQuestionEVAL vs MULTI?+

    Answer

    Lua can branch on reads; MULTI queues fixed commands only.
    3IntermediateQuestionSafe lock unlock?+

    Answer

    Lua: DEL only if GET equals unique token.
    4IntermediateQuestionEVALSHA benefit?+

    Answer

    Avoids sending full script body each call after SCRIPT LOAD.
    5AdvancedQuestionLua on Redis Cluster?+

    Answer

    All keys referenced must hash to same slot — use hash tags {user}:lock.

    Summary

    Lua = atomic custom logic on server.

    Ready to mark this lesson complete?Track your journey across the entire course.