VALKEY-LUA-API(7)
β¨ NAME β¨
okay so bestie, welcome to VALKEY-LUA-API(7) β straight outta the Valkey Manual, and this is the Lua API reference π
π
valkey-lua-api β Lua API reference π¦
π DESCRIPTION π
Valkey ships with an embedded Lua 5.1 interpreter, no cap. That interpreter runs the user-defined valkey-eval-intro(7) ephemeral scripts and valkey-functions-intro(7) functions. Scripts run in a sandboxed context and can only touch specific Lua packages. This page is the full tour of the packages and APIs you can use inside the executionβs context. β¨
π«§ Sandbox context π«§
The sandboxed Lua context is lowkey trying to prevent accidental misuse and reduce potential threats from the serverβs environment.
Scripts should never try to access the Valkey serverβs underlying host systems. That includes the file system, the network, and any other attempt to perform a system call other than those supported by the API.
Scripts should operate solely on data stored in Valkey and data provided as arguments to their execution. Periodt.
π± Global variables and functions π±
The sandboxed Lua execution context blocks the declaration of global variables and functions. The blocking of global variables is in place to ensure that scripts and functions donβt attempt to maintain any runtime context other than the data stored in Valkey. In the (somewhat uncommon) use case that a context needs to be maintain between executions, you should store the context in Valkeyβ keyspace.
Valkey will return an error when trying to execute the following snippet:
my_global_variable = 'some value'
And similarly for the following global function declaration:
function my_global_function()
-- Do something amazing
end
Youβll also get a similar error when your script attempts to access any global variables that are undefined in the runtimeβs context:
-- The following will surely raise an error
return an_undefined_global_variable
Instead, all variable and function definitions are required to be declared as local. To do so, youβll need to prepend the local keyword to your declarations. For example, the following snippet will be considered perfectly valid by Valkey:
local my_local_variable = 'some value'
local function my_local_function()
-- Do something else, but equally amazing
end
Note: the sandbox attempts to prevent the use of globals. Using Luaβs debugging functionality or other approaches such as altering the meta table used for implementing the globalsβ protection to circumvent the sandbox isnβt hard. However, it is difficult to circumvent the protection by accident. If the user messes with the Lua global state, the consistency of AOF and replication canβt be guaranteed. In other words, just donβt do it. π
π¦ Imported Lua modules π¦
Using imported Lua modules is not supported inside the sandboxed execution context. The sandboxed execution context prevents the loading modules by disabling Luaβs require function.
The only libraries that Valkey ships with and that you can use in scripts are listed under the Runtime libraries section. π
π Runtime globals π
While the sandbox prevents users from declaring globals, the execution context is pre-populated with several of these.
For some of them, a βsince versionβ is specified. The ones without βsince versionβ specified are available in all maintained versions.
π The KEYS global variable π
- Available in scripts: yes
- Available in functions: no
Important: to ensure the correct execution of scripts, both in standalone and clustered deployments, all names of keys that a function accesses must be explicitly provided as input key arguments. The script should only access keys whose names are given as input arguments. Scripts should never access keys with programmatically-generated names or based on the contents of data structures stored in the database.
The KEYS global variable is available only for valkey-eval-intro(7) ephemeral scripts. It is pre-populated with all key name input arguments.
π The ARGV global variable π
- Available in scripts: yes
- Available in functions: no
The ARGV global variable is available only in valkey-eval-intro(7) ephemeral scripts. It is pre-populated with all regular input arguments.
π The server singleton π
- Since version:
7.2.5 - Available in scripts: yes
- Available in functions: yes
The server singleton is an object instance thatβs accessible from all scripts. It provides the API to interact with Valkey from scripts. Following is the API provided by the server object instance.
Note: For compatibility with Redis, Valkey also exposes aredistop-level object, that exposes the exact same set of APIs as theserverobject. Valkey does not intend to drop compatibility for thisredisAPI, but it is recommended to use theserverobject for newly developed scripts.
π§Έ server object fields (functions and variables) π§Έ
π server.call(command [,arg...]) π
- Available in scripts: yes
- Available in functions: yes
The server.call() function calls a given Valkey command and returns its reply. Its inputs are the command and arguments, and once called, it executes the command in Valkey and returns the reply.
For example, we can call the ECHO command from a script and return its reply like so:
return server.call('ECHO', 'Echo, echo... eco... o...')
If and when server.call() triggers a runtime exception, the raw exception is raised back to the user as an error, automatically. Therefore, attempting to execute the following ephemeral script will fail and generate a runtime exception because ECHO accepts exactly one argument:
127.0.0.1:6379> EVAL "return server.call('ECHO', 'Echo,', 'echo... ', 'eco... ', 'o...')" 0
(error) ERR Wrong number of args calling Valkey command from script script: b0345693f4b77517a711221050e76d24ae60b7f7, on @user_script:1.
Note that the call can fail due to various reasons, see valkey-eval-intro(7) Execution under low memory conditions and Script flags
To handle Valkey runtime errors use server.pcall() instead.
π‘οΈ server.pcall(command [,arg...]) π‘οΈ
- Available in scripts: yes
- Available in functions: yes
This function enables handling runtime errors raised by the Valkey server. The server.pcall() function behaves exactly like server.call(), except that it:
- Always returns a reply.
- Never throws a runtime exception, and returns in its stead a
server.error_replyin case that a runtime exception is thrown by the server.
The following demonstrates how to use server.pcall() to intercept and handle runtime exceptions from within the context of an ephemeral script.
local reply = server.pcall('ECHO', unpack(ARGV))
if reply['err'] ~= nil then
-- Handle the error sometime, but for now just log it
server.log(server.LOG_WARNING, reply['err'])
reply['err'] = 'ERR Something is wrong, but no worries, everything is under control'
end
return reply
Evaluating this script with more than one argument will return:
127.0.0.1:6379> EVAL "..." 0 hello world
(error) ERR Something is wrong, but no worries, everything is under control
π server.error_reply(x) π
- Available in scripts: yes
- Available in functions: yes
This is a helper function that returns an valkey-protocol(7) error reply. The helper accepts a single string argument and returns a Lua table with the err field set to that string.
The outcome of the following code is that error1 and error2 are identical for all intents and purposes:
local text = 'ERR My very special error'
local reply1 = { err = text }
local reply2 = server.error_reply(text)
Therefore, both forms are valid as means for returning an error reply from scripts:
127.0.0.1:6379> EVAL "return { err = 'ERR My very special table error' }" 0
(error) ERR My very special table error
127.0.0.1:6379> EVAL "return server.error_reply('ERR My very special reply error')" 0
(error) ERR My very special reply error
For returning Valkey status replies refer to server.status_reply(). Refer to the Data type conversion for returning other response types.
Note: By convention, Valkey uses the first word of an error string as a unique error code for specific errors or ERR for general-purpose errors. Scripts are advised to follow this convention, as shown in the example above, but this is not mandatory.
β server.status_reply(x) β
- Available in scripts: yes
- Available in functions: yes
This is a helper function that returns a valkey-protocol(7) simple string reply. βOKβ is an example of a standard Valkey status reply. The Lua API represents status replies as tables with a single field, ok, set with a simple status string.
The outcome of the following code is that status1 and status2 are identical for all intents and purposes:
local text = 'Frosty'
local status1 = { ok = text }
local status2 = server.status_reply(text)
Therefore, both forms are valid as means for returning status replies from scripts:
127.0.0.1:6379> EVAL "return { ok = 'TICK' }" 0
TICK
127.0.0.1:6379> EVAL "return server.status_reply('TOCK')" 0
TOCK
For returning Valkey error replies refer to server.error_reply(). Refer to the Data type conversion for returning other response types.
π server.sha1hex(x) π
- Available in scripts: yes
- Available in functions: yes
This function returns the SHA1 hexadecimal digest of its single string argument.
You can, for example, obtain the empty stringβs SHA1 digest:
127.0.0.1:6379> EVAL "return server.sha1hex('')" 0
"da39a3ee5e6b4b0d3255bfef95601890afd80709"
π’ server.log(level, message) π’
- Available in scripts: yes
- Available in functions: yes
This function writes to the Valkey server log.
It expects two input arguments: the log level and a message. The message is a string to write to the log file. Log level can be one of these:
server.LOG_DEBUGserver.LOG_VERBOSEserver.LOG_NOTICEserver.LOG_WARNING
These levels map to the serverβs log levels. The log only records messages equal or greater in level than the serverβs loglevel configuration directive.
The following snippet:
server.log(server.LOG_WARNING, 'Something is terribly wrong')
will produce a line similar to the following in your serverβs log:
[32343] 22 Mar 15:21:39 # Something is terribly wrong
π server.setresp(x) π
- Available in scripts: yes
- Available in functions: yes
okay so this function lets the script you're running flip between valkey-protocol(7) RESP protocol versions for the replies that come back from server.call() and server.pcall(). It wants one numerical argument β the protocol version. Default is 2, but you can switch it up to version 3. π
Here's the glow-up in action β switching to RESP3 replies:
server.setresp(3)
Wanna know how all the types get translated? Skim over to Data type conversion further down. β¨
π¦ server.set_repl(x) π¦
- Available in scripts: yes
- Available in functions: no
Note: back in the day, before Redis OSS 7.0, scripts were replicated verbatim by default. Since Redis OSS 7.0 (and Valkey, bestie), script effects replication is the only replication mode that exists. no alternatives, periodt.
The server.set_repl() function tells the server how to treat the write commands that come after it, replication-wise. It takes a single input argument, and it can only be one of these:
server.REPL_ALL: replicates the effects to the AOF and the replicas.server.REPL_AOF: replicates the effects to the AOF alone.server.REPL_REPLICA: replicates the effects to the replicas alone.server.REPL_SLAVE: same asREPL_REPLICA, kept around for backward compatibility.server.REPL_NONE: disables effect replication entirely.
By default, the scripting engine starts out at server.REPL_ALL the moment a script begins running. You can call server.set_repl() at literally any point during the script's execution to hop between the different replication modes. π¦
A lil example, because examples slay:
server.replicate_commands() -- Enable effects replication in versions lower than Redis OSS v7.0
server.call('SET', KEYS[1], ARGV[1])
server.set_repl(server.REPL_NONE)
server.call('SET', KEYS[2], ARGV[2])
server.set_repl(server.REPL_ALL)
server.call('SET', KEYS[3], ARGV[3])
If you run this by calling EVAL "..." 3 A B C 1 2 3, the result is that only the keys A and C get created on the replicas and in the AOF. B? Not invited. π
πΈ server.replicate_commands() πΈ
- Until version: 7.0.0
- Available in scripts: yes
- Available in functions: no
This one switches the script's replication mode from verbatim replication over to effects replication. You can use it to override the default verbatim script replication mode that Redis OSS used right up until version 7.0.
Note: verbatim script replication is no longer supported. The only script replication mode that exists now is script effects' replication. For the whole story, go read valkey-eval-intro(7) under Replicating commands instead of scripts.
π server.breakpoint() π
- Available in scripts: yes
- Available in functions: no
This function drops a breakpoint when you're using the valkey-ldb(7) Valkey Lua debugger. Debugging era. π
π server.debug(x) π
- Available in scripts: yes
- Available in functions: no
This prints its argument right into the valkey-ldb(7) Valkey Lua debugger console. Your lil console.log, but make it Valkey.
π server.acl_check_cmd(command [,arg...]) π
- Since version: 7.0.0
- Available in scripts: yes
- Available in functions: yes
This function is your permission-checker: it asks whether the current user running the script actually has valkey-acl(7) permissions to execute the given command with the given arguments.
The return value is a boolean β true if the current user can run that command (like, via a call to server.call or server.pcall), and false if they can't. π
And heads up: the function will raise an error if the command you passed, or its arguments, are invalid.
β¨ server.register_function β¨
- Since version: 7.0.0
- Available in scripts: no
- Available in functions: yes
This function is only available from the context of the FUNCTION LOAD command. When you call it, it registers a function to the loaded library. You can call it with positional arguments or with named arguments β dealer's choice. π«Ά
π positional arguments: server.register_function(name, callback)
The first argument to server.register_function is a Lua string that represents the function name. The second argument is a Lua function.
Usage example:
127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib\n server.register_function('noop', function() end)"
π Named arguments: server.register_function{function_name=name, callback=callback, flags={flag1, flag2, ..}, description=description}
The named-arguments variant accepts all of these:
function_name: the function's name.callback: the function's callback.flags: an array of strings, each one a function flag (optional).description: the function's description (optional).
Both function_name and callback are mandatory. No skipping those, bestie.
Usage example:
127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib\n server.register_function{function_name='noop', callback=function() end, flags={ 'no-writes' }, description='Does nothing'}"
π₯ Script flags π₯
Important: use script flags with care β misuse can genuinely negatively impact stuff. And note that the defaults for Eval scripts are different from the defaults for functions mentioned below, so go see valkey-eval-intro(7) under Eval Flags.
When you register a function or load an Eval script, the server has no idea how that script touches the database. By default, Valkey just assumes all scripts read and write data. That assumption gives you this behavior:
- They can read and write data.
- They can run in cluster mode, and they are not able to run commands that access keys of different hash slots.
- Execution against a stale replica is denied, to avoid inconsistent reads.
- Execution under low memory is denied, to avoid exceeding the configured threshold.
You can use the following flags to tell the server to treat the script's execution differently:
no-writes: this flag says the script only reads data and never writes.
By default, Valkey will deny execution of flagged scripts (Functions and Eval scripts with the valkey-eval-intro(7) shebang) against read-only replicas, since they might try to write. Same energy with FCALL_RO / EVAL_RO β the server won't allow calling scripts with them. And lastly, when data persistence is at risk because of a disk error, execution gets blocked too.
Using this flag lets the script execute:
- With
FCALL_RO/EVAL_RO - On read-only replicas.
- Even if there's a disk error (Valkey can't persist, so it rejects writes).
- When over the memory limit, since it implies the script doesn't increase memory consumption (see
allow-oombelow).
But watch out: the server will return an error if the script tries to call a write command. Also, currently PUBLISH, SPUBLISH and PFCOUNT are also considered write commands in scripts, because they could attempt to propagate commands to replicas and the AOF file.
For more info, please refer to valkey-programmability(7) under Read-only scripts.
allow-oom: use this flag to let a script execute when the server is out of memory (OOM).
Unless you use it, Valkey will deny execution of flagged scripts (Functions and Eval scripts with the valkey-eval-intro(7) shebang) whenever it's in an OOM state. And bonus: when you use this flag, the script can call any Valkey command, including commands that usually aren't allowed in that state. Specifying no-writes or using FCALL_RO / EVAL_RO also implies the script can run in OOM state (without specifying allow-oom). β¨
allow-stale: a flag that enables running the flagged scripts (Functions and Eval scripts with thevalkey-eval-intro(7)shebang) against a stale replica when thereplica-serve-stale-dataconfig is set tono.
Valkey can be configured to prevent data consistency problems from using old data by having stale replicas return a runtime error. For scripts that don't access the data, this flag can be set to let stale Valkey replicas run the script. Note though: the script will still be unable to execute any command that accesses stale data.
no-cluster: this flag makes the script return an error in Valkey cluster mode.
Valkey lets scripts run in both standalone and cluster modes. Setting this flag prevents executing the script against nodes in the cluster.
allow-cross-slot-keys: the flag that lets a script access keys from multiple slots.
Valkey normally prevents any single command from accessing keys that hash to multiple slots. This flag lets scripts break that rule and access keys within the script that span multiple slots. Declared keys to the script are still always required to hash to a single slot. Accessing keys from multiple slots is discouraged, because applications should be designed to only access keys from a single slot at a time, which lets slots move between Valkey servers.
This flag has no effect when cluster mode is disabled.
Please refer to valkey-functions-intro(7) under Function Flags and valkey-eval-intro(7) under Eval Flags for a detailed example. π
π server.SERVER_VERSION π
- Since version: 7.2.5
- Available in scripts: yes
- Available in functions: yes
Returns the current Valkey server version as a Lua string. The reply's format is MM.mm.PP, where:
MM: is the major version.mm: is the minor version.PP: is the patch level.
π server.REDIS_VERSION π
- Since version: 7.0.0
- Available in scripts: yes
- Available in functions: yes
Returns the current Redis compatibility version as a Lua string. The reply's format is MM.mm.PP, where:
MM: is the major version.mm: is the minor version.PP: is the patch level.
β server.SERVER_VERSION_NUM β
- Since version: 7.2.5
- Available in scripts: yes
- Available in functions: yes
Returns the current Valkey server version as a number. The reply is a hexadecimal value structured as 0x00MMmmPP, where:
MM: is the major version.mm: is the minor version.PP: is the patch level.
π§ server.REDIS_VERSION_NUM π§
- Since version: 7.0.0
- Available in scripts: yes
- Available in functions: yes
Returns the current Redis compatibility version as a number. The reply is a hexadecimal value structured as 0x00MMmmPP, where:
MM: is the major version.mm: is the minor version.PP: is the patch level.
π Data type conversion π
Unless a runtime exception gets raised, server.call() and server.pcall() hand the reply from the executed command straight back to the Lua script. Valkey's replies from these functions get converted automatically into Lua's native data types. No manual labor required, bestie. π¦
Similarly, when a Lua script hands a reply back with the return keyword, that reply gets auto-converted to RESP protocol. no extra steps bestie, it just happens π«
Put differently: there's a one-to-one mapping between Valkey's replies and Lua's data types, and a one-to-one mapping between Lua's data types and the valkey-protocol(7) RESP Protocol data types. The underlying design is so clean β if a RESP type gets converted into a Lua type and then converted back into a RESP type, the result is the same as the initial value. round trip, no notes, iconic behavior π
Type conversion from Valkey replies (i.e. the replies from server.call() and server.pcall()) to Lua data types depends on the RESP protocol version used by the script. The default protocol version during script executions is RESP2. The script may switch the replies' protocol versions by calling the server.setresp() function.
Type conversion from a script's returned Lua data type depends on the user's choice of protocol (see the HELLO command).
The following sections describe the type conversion rules between Lua and Valkey per the protocol's version.
β¨ RESP2 to Lua type conversion β¨
The following type conversion rules apply to the execution's context by default as well as after calling server.setresp(2):
valkey-protocol(7)RESP2 integer reply -> Lua numbervalkey-protocol(7)RESP2 bulk string reply -> Lua stringvalkey-protocol(7)RESP2 array reply -> Lua table (may have other Valkey data types nested)valkey-protocol(7)RESP2 status reply -> Lua table with a singleokfield containing the status stringvalkey-protocol(7)RESP2 error reply -> Lua table with a singleerrfield containing the error stringvalkey-protocol(7)RESP2 null bulk reply and null multi bulk reply -> Luafalseboolean type
β¨ Lua to RESP2 type conversion β¨
The following type conversion rules apply by default as well as after the user had called HELLO 2:
- Lua number ->
valkey-protocol(7)RESP2 integer reply (the number is converted into an integer) - Lua string ->
valkey-protocol(7)RESP bulk string reply - Lua table (indexed, non-associative array) ->
valkey-protocol(7)RESP2 array reply (truncated at the first Luanilvalue encountered in the table, if any) - Lua table with a single
okfield ->valkey-protocol(7)RESP2 status reply - Lua table with a single
errfield ->valkey-protocol(7)RESP2 error reply - Lua boolean
false->valkey-protocol(7)RESP2 null bulk reply
There is an additional Lua-to-Valkey conversion rule that has no corresponding Valkey-to-Lua conversion rule:
- Lua Boolean
true->valkey-protocol(7)RESP2 integer reply with value of1.
There are three additional rules to note about converting Lua to Valkey data types:
- Lua has a single numerical type, Lua numbers. There is no distinction between integers and floats. So we always convert Lua numbers into integer replies, removing the decimal part of the number, if any. If you want to return a Lua float, it should be returned as a string, exactly like Valkey itself does (see, for instance, the
ZSCOREcommand). - There's no simple way to have
nils inside Lua arrays due to Lua's table semantics. Therefore, when Valkey converts a Lua array to RESP, the conversion stops when it encounters a Luanilvalue. - When a Lua table is an associative array that contains keys and their respective values, the converted Valkey reply will not include them. (rude, but true π)
Lua to RESP2 type conversion examples:
127.0.0.1:6379> EVAL "return 10" 0
(integer) 10
127.0.0.1:6379> EVAL "return { 1, 2, { 3, 'Hello World!' } }" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
1) "Hello World!"
127.0.0.1:6379> EVAL "return server.call('get','foo')" 0
"bar"
The last example demonstrates receiving and returning the exact return value of server.call() (or server.pcall()) in Lua as it would be returned if the command had been called directly. chef's kiss π«Ά
The following example shows how floats and arrays that cont nils and keys are handled:
127.0.0.1:6379> EVAL "return { 1, 2, 3.3333, somekey = 'somevalue', 'foo', nil , 'bar' }" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"
As you can see, the float value of 3.333 gets converted to an integer 3, the somekey key and its value are omitted, and the string "bar" isn't returned as there is a nil value that precedes it. it's giving "trust the process" π
β¨ RESP3 to Lua type conversion β¨
RESP3 is a newer version of the valkey-protocol(7) used by Valkey. It is available as an opt-in choice.
An executing script may call the server.setresp function during its execution and switch the protocol version that's used for returning replies from Valkey's commands (that can be invoked via server.call() or server.pcall()).
Once Valkey's replies are in RESP3 protocol, all of the RESP2 to Lua conversion rules apply, with the following additions:
valkey-protocol(7)Map reply -> Lua table with a singlemapfield containing a Lua table representing the fields and values of the map.valkey-protocol(7)Set reply -> Lua table with a singlesetfield containing a Lua table representing the elements of the set as fields, each with the Lua Boolean value oftrue.valkey-protocol(7)Null -> Luanil.valkey-protocol(7)True reply -> Luatrueboolean value.valkey-protocol(7)False reply -> Luafalseboolean value.valkey-protocol(7)Double reply -> Lua table with a singledoublefield containing a Lua number representing the double value.valkey-protocol(7)Big number reply -> Lua table with a singlebig_numberfield containing a Lua string representing the big number value (since Redis OSS 7.0).valkey-protocol(7)Verbatim string reply -> Lua table with a singleverbatim_stringfield containing a Lua table with two fields,stringandformat, representing the verbatim string and its format, respectively (since Redis OSS 7.0).
β¨ Lua to RESP3 type conversion β¨
Regardless of the script's choice of protocol version set for replies with the [server.setresp() function] when it calls server.call() or server.pcall(), the user may opt-in to using RESP3 (with the HELLO 3 command) for the connection. Although the default protocol for incoming client connections is RESP2, the script should honor the user's preference and return adequately-typed RESP3 replies, so the following rules apply on top of those specified in the Lua to RESP2 type conversion section when that is the case.
- Lua Boolean ->
valkey-protocol(7)RESP3 Boolean reply (note that this is a change compared to the RESP2, in which returning a Boolean Luatruereturned the number1to the Valkey client, and returning afalseused to return a null. - Lua table with a single
mapfield set to an associative Lua table ->valkey-protocol(7)RESP3 map reply. - Lua table with a single
setfield set to an associative Lua table ->valkey-protocol(7)RESP3 set reply. Values can be set to anything and are discarded anyway. - Lua table with a single
doublefield to an associative Lua table ->valkey-protocol(7)RESP3 double reply. - Lua
nil->valkey-protocol(7)RESP3 null.
However, if the connection is set use the RESP2 protocol, and even if the script replies with RESP3-typed responses, Valkey will automatically perform a RESP3 to RESP2 conversion of the reply as is the case for regular commands. That means, for example, that returning the RESP3 map type to a RESP2 connection will result in the reply being converted to a flat RESP2 array that consists of alternating field names and their values, rather than a RESP3 map. Valkey said "I'll translate" π
β¨ Additional notes about scripting β¨
π Using SELECT inside scripts π
You can call the SELECT command from your Lua scripts, like you can with any normal client connection. The database selected by the Lua script only affects the execution context of the script, and does not modify the database that's selected by the client calling the script. no crossover episodes here bestie β¨
π Runtime libraries π
The Valkey Lua runtime context always comes with several pre-imported libraries.
The following standard Lua libraries are available to use:
- The String Manipulation (
string) library - The Table Manipulation (
table) library - The Mathematical Functions (
math) library - The Operating System Facilities (
os) library
In addition, the following external libraries are loaded and accessible to scripts:
- The
structlibrary - The
cjsonlibrary - The
cmsgpacklibrary - The
bitoplibrary
π os library π
- Since version: 8.0.0
- Available in scripts: yes
- Available in functions: yes
os provides a set of functions for dealing with date, time, and system commands. More details can be found in the Operating System Facilities. Note that for sandbox security, currently only the following os functions is exposed:
os.clock()
π struct library π
- Available in scripts: yes
- Available in functions: yes
struct is a library for packing and unpacking C-like structures in Lua. It provides the following functions:
struct.pack()struct.unpack()struct.size()
All of struct's functions expect their first argument to be a format string.
π struct formats π
The following are valid format strings for struct's functions:
>: big endian<: little endian![num]: alignmentx: paddingb/B: signed/unsigned byteh/H: signed/unsigned shortl/L: signed/unsigned longT:size_ti/In: signed/unsigned integer with sizen(defaults to the size ofint)cn: sequence ofnchars (from/to a string); when packing,n == 0means the whole string; when unpacking,n == 0means use the previously read number as the string's length.s: zero-terminated stringf: floatd: double(space): ignored
π struct.pack(x) π
This function returns a struct-encoded string from values. It accepts a struct format string as its first argument, followed by the values that are to be encoded.
Usage example:
127.0.0.1:6379> EVAL "return struct.pack('HH', 1, 2)" 0
"\x01\x00\x02\x00"
π struct.unpack(x) π
This function returns the decoded values from a struct. It accepts a struct format string as its first argument, followed by encoded struct's string.
Usage example:
127.0.0.1:6379> EVAL "return { struct.unpack('HH', ARGV[1]) }" 0 "\x01\x00\x02\x00"
1) (integer) 1
2) (integer) 2
3) (integer) 5
struct.size(x)
This one returns the size of a struct in bytes, and its only argument is a struct format string. That's the whole thing. No notes. π
Usage example:
127.0.0.1:6379> EVAL "return struct.size('HH')" 0
(integer) 4
cjson library β¨
- Available in scripts: yes
- Available in functions: yes
okay so the cjson library is your girl for fast JSON encoding and decoding straight from Lua. She brings these functions to the group chat:
cjson.encode(x)
Hand it a Lua data type and it hands you back a JSON-encoded string. Literally that simple, no cap.
Usage example:
127.0.0.1:6379> EVAL "return cjson.encode({ ['foo'] = 'bar' })" 0
"{\"foo\":\"bar\"}"
cjson.decode(x)
The other direction bestie: you give it a JSON-encoded string and it gives you back a Lua data type. π
Usage example:
127.0.0.1:6379> EVAL "return cjson.decode(ARGV[1])['foo']" 0 '{"foo":"bar"}'
"bar"
cmsgpack library π
- Available in scripts: yes
- Available in functions: yes
The cmsgpack library does fast MessagePack encoding and decoding from Lua. It's giving cjson's chaotic cousin, and honestly? obsessed. π¦
cmsgpack.pack(x)
Give it a Lua data type, get back the packed string encoding of it. π
Usage example:
127.0.0.1:6379> EVAL "return cmsgpack.pack({'foo', 'bar', 'baz'})" 0
"\x93\xa3foo\xa3bar\xa3baz"
cmsgpack.unpack(x)
Feed it your string argument and it decodes that thing into the unpacked values. Reverse card, played. π
Usage example:
127.0.0.1:6379> EVAL "return cmsgpack.unpack(ARGV[1])" 0 "\x93\xa3foo\xa3bar\xa3baz"
1) "foo"
2) "bar"
3) "baz"
bit library π
- Available in scripts: yes
- Available in functions: yes
The bit library is all about bitwise operations on numbers. Its documentation resides at Lua BitOp documentation (go read it, bestie, it's iconic). It provides the following functions:
bit.tobit(x)
Normalizes a number into the numeric range for bit operations and returns it. It's basically a vibe check for your integer. β¨
Usage example:
127.0.0.1:6379> EVAL 'return bit.tobit(1)' 0
(integer) 1
bit.tohex(x [,n])
Converts its first argument into a hex string. The number of hex digits is given by the absolute value of the optional second argument. π’
Usage example:
127.0.0.1:6379> EVAL 'return bit.tohex(422342)' 0
"000671c6"
bit.bnot(x)
Returns the bitwise not of its argument. Simple. Elegant. Slays. π«Ά
bit.bor(x1 [,x2...]), bit.band(x1 [,x2...]) and bit.bxor(x1 [,x2...])
These return either the bitwise or, the bitwise and, or the bitwise xor of all of their arguments. And heads up β more than two arguments are allowed, so go feral with it. π₯
Usage example:
127.0.0.1:6379> EVAL 'return bit.bor(1,2,4,8,16,32,64,128)' 0
(integer) 255
bit.lshift(x, n), bit.rshift(x, n) and bit.arshift(x, n)
Returns either the bitwise logical left-shift, the bitwise logical right-shift, or the bitwise arithmetic right-shift of its first argument, by the number of bits given in the second argument. Slide to the left, slide to the right. ππΊ
bit.rol(x, n) and bit.ror(x, n)
Returns either the bitwise left rotation or the bitwise right rotation of its first argument, by the number of bits given in the second argument. The bits that get shifted out on one side are shifted right back in on the other side β recycling era, we love to see it. β»οΈ
bit.bswap(x)
Swaps the bytes of its argument and returns it. This can be used to convert little-endian 32-bit numbers into big-endian 32-bit numbers, and vice versa. Byte order glow-up, periodt. π§
and that's a wrap on the whole page, bestie!! π this was VALKEY-LUA-API(7), version 9.0.0, dated 2025-10-21 β go forth and write the most unhinged Lua scripts your little heart desires, you've got this, ily ππΈβ¨
π¦ where this page comes from
- fedora 44: valkey-doc 9.0.3-2.fc44 Β· CC-BY-SA-4.0
- fedora 44: valkey-doc 9.0.6-1.fc44 Β· CC-BY-SA-4.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms