Redis Lua scripting

Getting started

The following articles should help you get started with Lua scripting in Redis:


go-redis supports Lua scripting via redis.Scriptopen in new window struct. For exampleopen in new window, the following Lua script implements INCRBY command using GET and SET commands:

var incrBy = redis.NewScript(`
local key = KEYS[1]
local change = ARGV[1]

local value ="GET", key)
if not value then
  value = 0

value = value + change"SET", key, value)

return value

You can then run the script like this:

keys := []string{"my_counter"}
values := []interface{}{+1}
num, err := incrBy.Run(ctx, rdb, keys, values...).Int()

You can find the example above at GitHubopen in new window. For a more realistic example, check redis_rateopen in new window which implements a leacky bucket rate-limiter.

Lua and Go types

Lua's number type is a float64 number that is used to store both ints and floats. Because of that, Redis always converts Lua numbers into ints discarding the decimal part, for example, 3.14 becomes 3. If you want to return a float value, return it as a string and parse the string in Go using Float64open in new window helper.

Lua returnGo interface{}
number (float64)int64 (decimal is discarded)
falseredis.Nil error
{ok = "status"}string("status")
{err = "error message"}errors.New("error message")
{"foo", "bar"}[]interface{}{"foo", "bar"}
{foo = "bar", bar = "baz"}[]interface{}{} (not supported)

Debugging Lua scripts

The easiest way to debug your Lua scripts is using redis.log function that writes the message to the Redis log file or redis-server output:

redis.log(redis.LOG_NOTICE, "key", key, "change", change)

If you prefer a debugger, check Redis Lua scripts debuggeropen in new window.

Passing multiple values

You can use Lua for loop to iterate over the passed values. For example, to sum the passed numbers:

local key = KEYS[1]

local sum ="GET", key)
if not sum then
  sum = 0

local num_arg = #ARGV
for i = 1, num_arg do
  sum = sum + ARGV[i]
end"SET", key, sum)

return sum

The result:

sum, err := sum.Run(ctx, rdb, []string{"my_sum"}, 1, 2, 3).Int()
fmt.Println(sum, err)
// Output: 6 nil

Loop continue

Lua does not support continue statements in loops, but you can emulate it with a nested repeat loop and a break statement:

local num_arg = #ARGV

for i = 1, num_arg do

  if true then
    do break end -- continue

until true

Error handling

By default, function raises a Lua error and stops program execution. If you want to handle errors, use redis.pcall function which returns a Lua table with an err field:

local result = redis.pcall("rename", "foo", "bar")
if type(result) == 'table' and result.err then
  redis.log(redis.LOG_NOTICE, "rename failed", result.err)

To return a custom error, use a Lua table:

return {err = "error message goes here"}