Usage
await redis.scriptLoad(script);
Loads a Lua script into the Redis server’s script cache without executing it. Returns the SHA-1 hash of the script, which can be used with EVALSHA to execute the script later.
Parameters
The Lua script to load into the server cache.
Response
The SHA-1 hash of the loaded script. This hash can be used with EVALSHA to execute the script.
Examples
Load a Simple Script
const script = "return ARGV[1]";
const sha1 = await redis.scriptLoad(script);
console.log(sha1); // e.g., "4e6d8fc8bb01276962cce5371fa795a7763657ae"
// Now execute it using EVALSHA
const result = await redis.evalsha(sha1, [], ["Hello World"]);
console.log(result); // "Hello World"
Load a Counter Script
const counterScript = `
local current = redis.call('GET', KEYS[1]) or 0
local next = current + tonumber(ARGV[1])
redis.call('SET', KEYS[1], next)
return next
`;
const sha1 = await redis.scriptLoad(counterScript);
// Execute the cached script multiple times
const count1 = await redis.evalsha(sha1, ["counter"], ["1"]);
const count2 = await redis.evalsha(sha1, ["counter"], ["5"]);
const count3 = await redis.evalsha(sha1, ["counter"], ["10"]);
console.log(count3); // 16 (1 + 5 + 10)
Load Multiple Scripts
const scripts = {
increment: `
local val = redis.call('INCR', KEYS[1])
return val
`,
decrement: `
local val = redis.call('DECR', KEYS[1])
return val
`,
reset: `
redis.call('SET', KEYS[1], 0)
return 0
`
};
// Load all scripts and store their hashes
const hashes = {
increment: await redis.scriptLoad(scripts.increment),
decrement: await redis.scriptLoad(scripts.decrement),
reset: await redis.scriptLoad(scripts.reset)
};
// Use the scripts
await redis.evalsha(hashes.reset, ["counter"], []);
const val1 = await redis.evalsha(hashes.increment, ["counter"], []);
const val2 = await redis.evalsha(hashes.increment, ["counter"], []);
const val3 = await redis.evalsha(hashes.decrement, ["counter"], []);
console.log(val3); // 1
Atomic Multi-Key Operations
const transferScript = `
local from_balance = tonumber(redis.call('GET', KEYS[1]) or 0)
local amount = tonumber(ARGV[1])
if from_balance >= amount then
redis.call('DECRBY', KEYS[1], amount)
redis.call('INCRBY', KEYS[2], amount)
return 1
else
return 0
end
`;
const sha1 = await redis.scriptLoad(transferScript);
// Initialize balances
await redis.set("account:alice", "100");
await redis.set("account:bob", "50");
// Transfer 30 from Alice to Bob
const success = await redis.evalsha(
sha1,
["account:alice", "account:bob"],
["30"]
);
if (success === 1) {
console.log("Transfer successful");
const aliceBalance = await redis.get("account:alice"); // "70"
const bobBalance = await redis.get("account:bob"); // "80"
}
Complex Data Processing
const batchUpdateScript = `
local key_prefix = ARGV[1]
local count = tonumber(ARGV[2])
local value = ARGV[3]
for i = 1, count do
local key = key_prefix .. ':' .. i
redis.call('SET', key, value)
end
return count
`;
const sha1 = await redis.scriptLoad(batchUpdateScript);
// Set user:1 through user:100 to "active"
const updated = await redis.evalsha(
sha1,
[],
["user", "100", "active"]
);
console.log(`Updated ${updated} keys`);
When to Use SCRIPT LOAD
Good Use Cases
- Frequently executed scripts: Load once, execute many times
- Application startup: Pre-load all scripts your application needs
- Performance optimization: Reduce bandwidth and parsing overhead
- Complex atomic operations: Ensure scripts are available before use
Example: Application Initialization
class RedisScripts {
private hashes: Record<string, string> = {};
async initialize(redis: Redis) {
const scripts = {
incrementCounter: `
local val = redis.call('INCR', KEYS[1])
return val
`,
checkAndSet: `
local current = redis.call('GET', KEYS[1])
if current == ARGV[1] then
redis.call('SET', KEYS[1], ARGV[2])
return 1
end
return 0
`,
getMultiple: `
local results = {}
for i, key in ipairs(KEYS) do
results[i] = redis.call('GET', key)
end
return results
`
};
// Load all scripts at startup
for (const [name, script] of Object.entries(scripts)) {
this.hashes[name] = await redis.scriptLoad(script);
}
}
async incrementCounter(redis: Redis, key: string) {
return redis.evalsha(this.hashes.incrementCounter, [key], []);
}
async checkAndSet(
redis: Redis,
key: string,
expected: string,
newValue: string
) {
return redis.evalsha(
this.hashes.checkAndSet,
[key],
[expected, newValue]
);
}
async getMultiple(redis: Redis, keys: string[]) {
return redis.evalsha(this.hashes.getMultiple, keys, []);
}
}
// Usage
const scripts = new RedisScripts();
await scripts.initialize(redis);
const count = await scripts.incrementCounter(redis, "visitors");
Script Caching Behavior
-
Scripts are cached on the Redis server until:
- The server restarts
- The script cache is explicitly flushed
- Memory pressure causes eviction (rare)
-
Scripts are not automatically replicated to read replicas. If using read replicas, you must load scripts on each instance.
Using the Script Class
Instead of manually managing SHA-1 hashes, use the Script class:
const script = redis.createScript<number>(`
local current = redis.call('GET', KEYS[1]) or 0
local next = current + tonumber(ARGV[1])
redis.call('SET', KEYS[1], next)
return next
`);
// The Script class automatically computes and caches the SHA-1 hash
const result = await script.exec(["counter"], ["1"]);
The Script class:
- Automatically computes the SHA-1 hash
- Optimistically tries EVALSHA first
- Falls back to EVAL if the script isn’t loaded
- Caches the script on the server after first use
See Also
- EVAL - Execute a Lua script
- EVALSHA - Execute a cached script by SHA-1 hash