Module A-3·10 min read

How Redis Functions differ from Lua scripts — functions persist across restarts in RDB/AOF. Function libraries, the shebang declaration, registering multiple functions in one library, replication semantics, and migration from EVALSHA.

Written by Jatin Jain Saraf · Architect of SupraScan

A-3 — Redis Functions: Persistent Stored Procedures

Who this module is for: You use EVALSHA to call Lua scripts by SHA digest and manage script lifecycle manually — re-loading scripts after restarts, distributing SHAs across application instances. Redis Functions (introduced in Redis 7.0) solve exactly these pain points. This module covers the Functions model, how it differs from EVAL/EVALSHA, and when to migrate.


The Problem with EVALSHA

SCRIPT LOAD + EVALSHA works, but has operational friction:

  1. Scripts do not persist — they live in a volatile in-memory cache. Redis restart = all scripts gone. Your application must re-load scripts on every startup (or handle NOSCRIPT errors).

  2. SHA distribution — every application instance needs to know the SHA digest of every script. If you deploy a new script version, every instance must get the new SHA simultaneously.

  3. No introspection — Redis cannot list what scripts are loaded. SCRIPT EXISTS sha tells you if a specific SHA is loaded, but you cannot ask "what scripts are in the cache?"

  4. No namespace — all scripts share one global namespace (the SHA cache). No way to group related scripts.

Redis Functions solve all four problems.


What Redis Functions Are

Redis Functions (Redis 7.0+) are named, persistent, typed server-side functions. They are stored in Redis like data — persisted to RDB/AOF, replicated to replicas, and survive restarts.

Key differences from EVAL scripts:

FeatureEVAL / EVALSHARedis Functions
PersistenceVolatile (cache)Durable (RDB + AOF)
NamingSHA digest onlyNamed (library + function name)
DiscoverySCRIPT EXISTS shaFUNCTION LIST
EngineLua onlyLua (+ future engines)
ReplicationCommand replicatedLibrary replicated
NamespaceGlobalPer-library

Function Library Anatomy

Functions are grouped into libraries. A library is a Lua module with a #! shebang declaring the engine and library name, plus one or more redis.register_function() calls:

#!lua name=mylib
 
-- Register a rate limiter function
redis.register_function('check_rate_limit', function(keys, args)
  local key = keys[1]
  local window = tonumber(args[1])
  local limit = tonumber(args[2])
  local now = tonumber(args[3])
  local window_start = now - window
 
  redis.call('ZREMRANGEBYSCORE', key, 0, window_start)
  local count = redis.call('ZCARD', key)
 
  if count >= limit then
    return 0
  end
 
  redis.call('ZADD', key, now, tostring(now) .. tostring(math.random(1000000)))
  redis.call('PEXPIRE', key, window)
  return 1
end)
 
-- Register a conditional set function
redis.register_function('set_if_greater', function(keys, args)
  local current = redis.call('ZSCORE', keys[1], args[1])
  if current == false or tonumber(args[2]) > tonumber(current) then
    redis.call('ZADD', keys[1], args[2], args[1])
    return 1
  end
  return 0
end)

Loading a Library

FUNCTION LOAD [REPLACE] function-code
# Load from command line
redis-cli FUNCTION LOAD "#!lua name=mylib\n\nredis.register_function('my_fn', function(keys, args)\n  return args[1]\nend)"
 
# Load from file
redis-cli FUNCTION LOAD "$(cat mylib.lua)"
 
# Replace existing library (update)
redis-cli FUNCTION LOAD REPLACE "$(cat mylib.lua)"

In Node.js:

import fs from 'fs';
 
const libraryCode = fs.readFileSync('./src/redis/mylib.lua', 'utf8');
 
async function loadFunctions() {
  try {
    await redis.call('FUNCTION', 'LOAD', libraryCode);
    console.log('Functions loaded');
  } catch (err: any) {
    if (err.message.includes('Library already exists')) {
      // Already loaded — skip (or use REPLACE to update)
      return;
    }
    throw err;
  }
}
 
// Call once at application startup
await loadFunctions();

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.