Lua Scripting Basics
Valkey supports server-side scripting using Lua, a lightweight, embeddable programming language. Lua scripts let you execute custom logic inside the Valkey server, providing atomicity and efficiency for tasks that would normally require multiple round trips or complex client-side coordination.
Traditionally, Lua scripting can be achieved through the various Valkey commmands like EVAL and EVALSHA.
GLIDE provides a more user friendly interface through the Script() class and various methods.
What You’ll Learn
Section titled “What You’ll Learn”This tutorial will cover:
- A brief overview of Lua Scripting in Valkey.
- Creaing a “Hello World” example with GLIDE.
- How return types are handled.
Why Use Lua Scripts?
Section titled “Why Use Lua Scripts?”Lua scripting has two primary benefits:
- Atomicity: The entire Lua script is executed as a single, atomic operation. Valkey guarantees that no other command or script will run in the midst of your script’s execution. This is perfect for complex “read-modify-write” patterns where you need to fetch data, perform logic on it, and write it back without interruption.
- Performance: Executing logic on the server reduces network latency. Instead of making multiple round-trips from your
application (e.g.,
GETa value, modify it,SETthe new value), you can send a single script that performs all operations on the server side.
You’ll learn more about how to use Lua script to enable safe atomic operations in the next tutorial.
For more on Lua scripting in Valkey, see the documentations.
Prerequisites
Section titled “Prerequisites”Before you begin, you’ll need a few things:
- Python: Valkey supports Python 3.9 to 3.13.
- Valkey GLIDE: You’ll need the
glide-clientlibrary. You can install it using pip:Terminal window pip install valkey-glide - Valkey Server: You need a running Valkey instance. The easiest way to get one is with Docker. Run this command in your terminal to start a standalone Valkey server:
Terminal window docker run -d --name standalone-valkey -p 6379:6379 -d valkey/valkey - A Basic knowledge of Lua.
Prepare hello_world.py.
Section titled “Prepare hello_world.py.”The following skeleton application connects to our Valkey docker container and will be used in the example. The connection is then tested using ping.
hello_world.py
import asynciofrom glide import ( Script, GlideClient, GlideClientConfiguration, NodeAddress, RequestError)
async def main(): print("Starting the GLIDE Lua tutorial...")
# Standalone client configuration config = GlideClientConfiguration(addresses=[NodeAddress("localhost", 6379)]) client = None # Define client outside try block
try: # Create and connect the client client = await GlideClient.create(config)
# Check for connection result = await client.ping() if not result: print("Error: Could not ping Valkey server. Check your connection with Valkey.") return
print("Successfully connected to Valkey.")
# Our script logic will go here
except RequestError as e: print(f"Error connecting or running command: {e}")
finally: if client: # Always close the client when done await client.close() print("Connection closed.")
if __name__ == "__main__": asyncio.run(main())Make sure to run the script to check for a successful connection
$ python hello_world.pyStarting the GLIDE Lua tutorial...Successfully connected to Valkey.Connection closed.A Simple “Hello World”
Section titled “A Simple “Hello World””We will create a Script object with our Lua code and execute it using client.invoke_script.
Add the following code block inside the try block after the client initialization.
# ... inside the try block ...print("Successfully connected to Valkey.")
# 1. Create a simple 'Hello World' scripthello_script = Script("return 'Hello, Valkey!'")
# 2. Execute the script on the serverresult = await client.invoke_script(hello_script)
# 3. Print the resultprint(f"Script result: {result}")Run your script again. You should see the following output:
$ python app.pyStarting the GLIDE Lua tutorial...Successfully connected to Valkey.Script result: b'Hello, Valkey!'Connection closed.Notice the b'...' prefix. Valkey and GLIDE return strings as raw bytes. This is the expected behavior.
Handling Different Return Values
Section titled “Handling Different Return Values”Lua scripts can return more than just strings. Let’s try returning a number and an array. Add this code after your “Hello World” script.
# ... after the 'Hello World' script ...
# Example 2: Script that returns a numbernum_script = Script("return 42")num_result = await client.invoke_script(num_script)print(f"Number script result: {num_result} (Type: {type(num_result)})")
# Example 3: Script that returns an array (list)array_script = Script("return {1, 2, 3, 'hello'}")array_result = await client.invoke_script(array_script)print(f"Array script result: {array_result}")Run the script again. See how GLIDE converts Lua types back to Python types:
...Number script result: 42 (Type: <class 'int'>)Array script result: [1, 2, 3, b'hello']...Full Example Code
import asynciofrom glide import ( Script, GlideClient, GlideClientConfiguration, NodeAddress, RequestError)
async def main(): print("Starting the GLIDE Lua tutorial...")
# Standalone client configuration config = GlideClientConfiguration(addresses=[NodeAddress("localhost", 6379)]) client = None # Define client outside try block
try: # Create and connect the client client = await GlideClient.create(config) print("Successfully connected to Valkey.")
# 1. Create a simple 'Hello World' script hello_script = Script("return 'Hello, Valkey!'") result = await client.invoke_script(hello_script) print(f"Script result: {result}")
# 2. Script that returns a number num_script = Script("return 42") num_result = await client.invoke_script(num_script) print(f"Number script result: {num_result} (Type: {type(num_result)})")
# 3. Script that returns an array (list) array_script = Script("return {1, 2, 3, 'hello'}") array_result = await client.invoke_script(array_script) print(f"Array script result: {array_result}")
except RequestError as e: print(f"Error connecting or running command: {e}")
finally: if client: # Always close the client when done await client.close() print("Connection closed.")
if __name__ == "__main__": asyncio.run(main())What’s Next
Section titled “What’s Next”Congratulations! You have learned how to execute an arbitrary Lua scripts in Valkey using GLIDE. To continue, see: