Skip to main content

Lua Scripting

Redis includes a built-in Lua interpreter that allows you to run server-side scripts using the command:

EVAL <script> <numkeys> key1 key2 arg1 arg2 ...

Why Lua Scripting Matters for Performance

When you execute multiple Redis commands from your application:

Without optimization

Your app → Redis → app → Redis (many round trips)

This creates:

  • high latency
  • many network packets
  • slow client-side logic

With Lua scripting

Your app → Redis (one script) → Redis runs everything internally

Huge performance improvements because:

  • 0 network round trips inside script
  • Atomicity guaranteed

Atomic Increment with Logic

Suppose you want: Increment a counter only if a limit is not exceeded.

Without Lua (multiple round trips):

  1. GET counter
  2. compute in app
  3. SET counter newValue

This can cause race conditions in concurrent environments.

EVAL "
local current = redis.call('GET', KEYS[1])
if not current then
redis.call('SET', KEYS[1], 1)
return 1
elseif tonumber(current) < tonumber(ARGV[1]) then
redis.call('INCR', KEYS[1])
return redis.call('GET', KEYS[1])
else
return current
end
" 1 counter 10
  • KEYS[1] = "counter"
  • ARGV[1] = 10 (limit)
  • Logic:
    • If counter doesn't exist → set to 1
    • If under limit → increment
    • If over limit → return current value
  • All done atomically and in one server-side script

Why Lua is Faster Than Multi-Command Client Logic

Because Redis runs Lua scripts without releasing the CPU until finished.

This makes it:

  • Safer (no race conditions)
  • Faster (no network calls)
  • More powerful (conditional logic on server)

Lua Scripting vs MULTI/EXEC

FeatureLua ScriptingMULTI/EXEC
Atomic?✔ Entire script atomic✔ Entire transaction atomic
Conditional logic?✔ Fully flexible❌ No logic inside transaction (client must compute)
Network round trips✔ 1 round trip❌ Multiple (commands are queued)
Performance⭐ Fastest for multi-ops⚡ Fast
Error behaviorScript runs fully or errors earlyErrors only on EXEC
Server-side loops?✔ Yes❌ No
Ideal forcomplex logic, repeated patternssimple atomic sequences

Lua Scripting vs Pipelining

Pipelining sends multiple commands in one batch but:

FeatureLua ScriptingPipelining
Atomic✔ Yes❌ No
Conditional logic✔ Yes❌ No
Network round trips✔ 1✔ 1
Executes server-side?✔ Yes❌ No (just client batching)
Order guarantee✔ Yes✔ Yes
Ideal forstateful logichigh-volume simple commands

Compare Lua, MULTI/EXEC, and Pipelining

Requirement: Increment three keys and return their sum

Approach 1: Without Optimization (3 round trips)

INCR k1
INCR k2
INCR k3
  • 3 network round trips
  • 3 server executions
  • client computes sum

Approach 2: Pipelining (1 round trip)

INCR k1
INCR k2
INCR k3

Sent as a pipeline → 1 round trip

BUT:

  • Still 3 server operations
  • No atomicity
  • Client computes last step

Approach 3: MULTI/EXEC (Atomic but more round trips)

MULTI
INCR k1
INCR k2
INCR k3
EXEC
  • ✔ atomic
  • ❌ 2 network round trips (MULTI + EXEC)
  • ❌ cannot compute sum server-side

Approach 4: Lua Scripting (Best)

EVAL "
local a = redis.call('INCR', KEYS[1])
local b = redis.call('INCR', KEYS[2])
local c = redis.call('INCR', KEYS[3])
return a + b + c
" 3 k1 k2 k3
  • 1 round trip
  • All increments occur inside Redis
  • Sum computed server-side
  • Atomic
  • Fastest option

Between Lua, MULTI/EXEC, and Pipelining

If you need…Use
Complex logicLua
Atomicity + logicLua
Many simple commands with no logicPipelining
Strict atomic multi-command bundleMULTI/EXEC
Server-side computation (loops, conditionals)Lua
Minimizing network latencyLua or Pipelining