Valkey modules are a powerful way to extend Valkey’s core functionality with custom data structures, commands, and features.

Let’s see Valkey modules in action. Imagine you want to add a time-series data structure to Valkey. Instead of building a complex solution on top of existing Valkey data types, you can use a module. For instance, the valkey-timeseries module provides commands like TS.ADD, TS.GET, and TS.RANGE that operate on time-series data directly within Valkey.

Here’s a simplified look at how you might interact with it:

# Add a data point to a time series
valkey-cli TS.ADD my_time_series * 100

# Get the latest data point from a time series
valkey-cli TS.GET my_time_series

# Get a range of data points
valkey-cli TS.RANGE my_time_series - + AGGREGATION sum 1000

The problem Valkey modules solve is the inherent limitation of a fixed set of commands and data types. While Valkey is incredibly versatile, there are specialized use cases that benefit from native, optimized implementations. Modules allow third-party developers and Valkey users to build these specialized features and integrate them seamlessly.

Internally, a Valkey module is a shared library (typically .so on Linux) that is loaded by the Valkey server at startup or dynamically. This library contains C functions that expose new commands and data types to Valkey. When a client sends a command that belongs to a module, Valkey routes that command to the loaded module for processing. The module then executes its custom logic, which might involve interacting with Valkey’s internal data structures or performing entirely independent operations, and returns the result to the client through Valkey.

You control module behavior primarily through configuration. When starting Valkey, you specify which modules to load and their associated configuration options. This is typically done in the valkey.conf file.

# Load the time-series module
loadmodule /usr/local/valkey/modules/valkey_timeseries.so

# Configure a specific option for the time-series module (example)
# module-config valkey-timeseries max-samples 10000

The loadmodule directive tells Valkey where to find the shared library. Some modules also accept configuration parameters, often prefixed with the module’s name, to fine-tune their behavior. These parameters are module-specific and documented by the module author.

The most surprising thing about Valkey modules is that they can fundamentally alter Valkey’s performance characteristics and even introduce entirely new persistence mechanisms, all without modifying Valkey’s core source code. A well-written module can feel as if it’s always been part of Valkey, offering optimized data structures and commands that outperform generic implementations built on top of standard Valkey types. For example, a module designed for graph databases can offer sub-millisecond traversals of complex relationships, something that would be prohibitively slow if simulated using Hash or Sorted Set commands alone. This extensibility is achieved through Valkey’s robust module API, which provides low-level access to the server’s internals, allowing modules to manage their own data, define custom serialization formats, and even hook into Valkey’s event loop for asynchronous operations.

The next step after successfully loading and using modules is understanding how to manage their lifecycle, including dynamic loading and unloading, and handling potential module conflicts.

Want structured learning?

Take the full Valkey course →