Skip to main content
Use EVAL to run a Lua script on the server. <numkeys> says how many of the arguments that follow are key names. The script receives those in the KEYS table and every remaining argument in ARGV. Passing key names as keys rather than hardcoding them in the script body matters, because Redis uses that list for routing and access checks. Inside the script, redis.call runs Redis commands and its return value is converted to a Lua value. The script runs as a single atomic step, which makes it the standard way to do read, decide, and write logic, such as a rate limiter or a compare-and-set update, in one round trip and without a transaction. Keep scripts short, since a script that holds the database blocks everything else, and keep them deterministic by deriving values from KEYS, ARGV, or data read inside the script rather than from clock or random sources. Upstash isolates a script with a lock. By default that is the global lock, because the engine cannot know in advance which keys the script will touch, so no other command runs while the script does. Adding the allow-key-locking flag to the script’s shebang line makes it lock only the keys passed in KEYS instead, so calls that work on disjoint keys run in parallel:
With the flag set, every key the script touches must appear in KEYS, and commands that need database-wide access, such as FLUSHDB, are rejected. See Key-Based Locking for the full rules.
Pass every key the script touches through KEYS, even when the script runs under the global lock. Upstash keeps idle entries on disk: declared keys are loaded before the script starts and the lock is released during that read, but a key that the script builds while it runs is read from disk with the lock held, stalling every command waiting on it. See Dynamic Keys and Latency.
Sending a script also caches it under its SHA1 digest, so later calls can use EVALSHA and avoid resending the body. Use EVAL_RO for scripts that only read.

Syntax

Arguments

Important points

  • numkeys must equal the number of key arguments that immediately follow it; remaining arguments are available to the script or function as ordinary arguments.
  • The script takes the global lock unless its shebang sets the allow-key-locking flag, in which case it locks only the keys passed in KEYS. See Key-Based Locking.
  • A script queued inside a MULTI/EXEC transaction always runs under the global lock, even when it sets allow-key-locking. Call it directly if you want per-key locking.
  • Pass every key the script touches through KEYS whether or not allow-key-locking is set. A key built inside the script is read from disk under the lock when it is not in memory, and it is rejected outright when the flag is set. See Dynamic Keys and Latency.

Response

The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below.
Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply.

Examples

TCP examples use the TLS REDIS_URL from the Upstash console. REST examples use UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN.

Related topics

EVALEVAL_ROEVALSHA