fivenines

Theory / 10 min

Scripts/functions

Redis commands are intentionally small. That is part of the server's speed. But real application logic often wants to combine several operations: read a value, branch on it, update one key, append to another, and return a decision.

If that logic stays entirely on the client, it can become slow and race-prone. Scripts and functions move that logic into Redis.

The core idea is:

client invokes server-side code -> code calls Redis operations -> Redis returns one result

While the script or function is running, Redis does not interleave other client commands through the same command execution path. That makes server-side programmability a powerful coordination tool.

Why Transactions Are Not Enough

Redis transactions queue commands and execute them later, but queued commands cannot branch on intermediate results.

Suppose an application wants to reserve inventory:

read stock
if stock > 0:
  decrement stock
  record order
else:
  reject order

With a plain transaction, the decision-making still has to happen outside the queued batch unless optimistic locking is used. A script can keep the read, branch, write, and reply together on the server.

Scripts As Atomic Server-Side Logic

Classic Redis scripting uses Lua through EVAL:

EVAL script numkeys key [key ...] arg [arg ...]

Inside the script, Redis exposes keys and arguments separately:

local stock = tonumber(redis.call("GET", KEYS[1]) or "0")
if stock <= 0 then
  return 0
end
redis.call("DECR", KEYS[1])
redis.call("LPUSH", KEYS[2], ARGV[1])
return 1

The distinction between KEYS and ARGV is not cosmetic. Redis needs to know which arguments are keys, especially for cluster routing and replication semantics. A script that hides key names inside arbitrary arguments is much harder for the system to reason about.

Functions As Managed Server Code

Redis functions move from "send this script body now" toward "load named libraries into the server and call them."

Conceptually:

load function library once
call named function with keys and args
function executes near the data

Functions make server-side logic easier to manage operationally. They can be versioned, listed, flushed, and called by name. The conceptual role is similar to scripts, but the lifecycle is more explicit and durable.

The Power And The Risk Are The Same

Scripts are powerful because they run inside Redis' command execution model. They are risky for the same reason.

A long-running script blocks other clients. A script that performs too much work violates the event loop's expectation of short command turns. A script that uses nondeterministic behavior can complicate replication. A script that accesses keys unclearly can break cluster expectations.

Server-side code should therefore be treated as part of the database engine's hot path, not as a general application runtime.

Replication And Determinism

Redis has to ensure replicas end up with the same dataset as the primary. With scripts, this can be handled by propagating the script invocation or by propagating the concrete write commands produced by the script, depending on mode and version.

The deeper point is that server-side code must not make replicas diverge. Randomness, time, and external effects need careful handling because the primary and replica cannot be allowed to make different decisions for the same logical operation.

The Right Mental Model

Scripts and functions are not a way to turn Redis into an application server. They are a way to express small, data-adjacent operations that need atomicity, lower latency, or both.

Used well, they remove round trips and close race windows. Used carelessly, they create latency spikes and operational surprises. The best server-side Redis code is short, explicit about its keys, and shaped like one command that Redis did not happen to ship with.

Next step

See what actually stuck.

Take the practice scenarios now.