Scripting commands
Goblin Core embeds six independent scripting interpreters. Each is reached through its own command prefix and keeps its own script cache and VM; they share nothing but the key space (one Store).
| Interpreter | Language | Commands |
|---|---|---|
| PUC-Lua 5.1 | the dialect real Redis scripts target | EVAL · EVALSHA · SCRIPT |
| Luau | Roblox's typed, sandboxed Lua | LUAU.EVAL · LUAU.EVALSHA · LUAU.SCRIPT |
| Wren | a small class-based language (wren.io) | WREN.EVAL · WREN.EVALSHA · WREN.SCRIPT |
| Jim Tcl | a small embeddable Tcl (jim.tcl.tk) | TCL.EVAL · TCL.EVALSHA · TCL.SCRIPT |
| MicroPython | a lean Python (micropython.org) | UPYTHON.EVAL · UPYTHON.EVALSHA · UPYTHON.SCRIPT |
| QuickJS | JavaScript (quickjs-ng) | QUICKJS.EVAL · QUICKJS.EVALSHA · QUICKJS.SCRIPT |
The data-type commands that share this key space are documented separately: strings (SET / GET / INCR / GETRANGE / …), lists (GOBLIN.PMA.LPUSH / GOBLIN.PMA.LINDEX / standard aliases / …), arrays (ARSET / GOBLIN.CLASSIC.AR* / GOBLIN.RT.AR* / …), keys (DEL / EXISTS / TYPE), and ttl (EXPIRE / TTL / PERSIST / …). The Pub/Sub reference covers subscriptions, publishing, introspection, wire-mode behavior, and slow consumers. Goblin Core's own additions — memory introspection, compaction, snapshots, and the native GOBLIN.CAD compare-and-delete — are in goblin.
Why more than one?
EVAL runs PUC-Lua 5.1 for bug-for-bug compatibility with other Redis implementations — scripts written for Redis run unchanged. The prefixed commands opt into a different interpreter: LUAU.EVAL gives you Luau, WREN.EVAL gives you Wren, QUICKJS.EVAL gives you JavaScript. They deliberately do not share behavior with EVAL, so choosing one is an explicit decision.
Concepts shared by all of them
- Arguments.
… EVAL script numkeys [key …] [arg …].numkeyssplits the trailing arguments into the keys the script touches and the plain args. They are exposed to the script asKEYSandARGV.
Indexing differs by language: Lua (EVAL,LUAU.EVAL) is 1-based
(KEYS[1]), while Wren (WREN.EVAL), Python (UPYTHON.EVAL), and
JavaScript (QUICKJS.EVAL) are 0-based (KEYS[0]); Tcl (TCL.EVAL)
exposes them as lists read withlindex([lindex $KEYS 0]).
- Atomicity. The server is single-threaded, so a script runs to completion with no other command interleaved. Every
redis.callinside a script executes against the same store synchronously.
- Calling commands. Scripts reach the data through a host binding (
redis.call/redis.pcallin Lua, Python, and JavaScript,Redis.call/Redis.pcallin Wren,redis call/redis pcallin Tcl) that re-enters the normal command pipeline. A script may not call another script command —EVAL,EVALSHA,SCRIPT, and theLUAU.*/WREN.*/TCL.*/UPYTHON.*/QUICKJS.*equivalents are rejected from inside a script.
- Script cache. Each interpreter caches scripts by the SHA1 of their source.
…EVALadds to the cache;…EVALSHAruns a cached script by its digest;…SCRIPT LOAD/EXISTS/FLUSHmanage the cache. The caches are independent: a script loaded withSCRIPT LOADis invisible toLUAU.EVALSHA,WREN.EVALSHA, andQUICKJS.EVALSHA, and vice versa.
- Sandbox. No interpreter can touch the filesystem, spawn processes, open network connections, or load host modules. See each command's page for the exact surface.
- Replication captures results. A script runs once on the primary, and its successful nested writes are emitted together as canonical post-state mutations. Replicas do not rerun the script, so nondeterministic library functions may remain enabled without producing a different result downstream.
Return values
A script's return value is converted to a RESP reply. The rules are analogous across the languages (numbers become integers, strings become bulk strings, arrays/lists become multi-bulk, a designated shape becomes a status or error reply). The exact table is on each …EVAL page.