{
  "id": "modules",
  "title": "Redis modules API",
  "url": "https://un5pn9hmggug.julianrbryant.com/docs/latest/develop/reference/modules/",
  "summary": "Introduction to writing Redis modules",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-04-01T08:10:08-05:00",
  "children": [
    {
      "id": "modules-api-ref",
      "summary": "Reference for the Redis Modules API",
      "title": "Modules API reference",
      "url": "https://un5pn9hmggug.julianrbryant.com/docs/latest/develop/reference/modules/modules-api-ref/"
    },
    {
      "id": "modules-blocking-ops",
      "summary": "How to implement blocking commands in a Redis module",
      "title": "Redis modules and blocking commands",
      "url": "https://un5pn9hmggug.julianrbryant.com/docs/latest/develop/reference/modules/modules-blocking-ops/"
    },
    {
      "id": "modules-native-types",
      "summary": "How to use native types in a Redis module",
      "title": "Modules API for native types",
      "url": "https://un5pn9hmggug.julianrbryant.com/docs/latest/develop/reference/modules/modules-native-types/"
    }
  ],
  "page_type": "content",
  "content_hash": "0cf264e8c818542446f66076c3fff3e64dc286aa71c44e87e867ec21635fa264",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "The modules documentation is composed of the following pages:\n\n* Introduction to Redis modules (this file). An overview about Redis Modules system and API. It's a good idea to start your reading here.\n* [Implementing native data types]() covers the implementation of native data types into modules.\n* [Blocking operations]() shows how to write blocking commands that will not reply immediately, but will block the client, without blocking the Redis server, and will provide a reply whenever will be possible.\n* [Redis modules API reference]() is generated from module.c top comments of RedisModule functions. It is a good reference in order to understand how each function works.\n\nRedis modules make it possible to extend Redis functionality using external\nmodules, rapidly implementing new Redis commands with features\nsimilar to what can be done inside the core itself.\n\nRedis modules are dynamic libraries that can be loaded into Redis at\nstartup, or using the [`MODULE LOAD`]() command. Redis exports a C API, in the\nform of a single C header file called `redismodule.h`. Modules are meant\nto be written in C, however it will be possible to use C++ or other languages\nthat have C binding functionalities.\n\nModules are designed in order to be loaded into different versions of Redis,\nso a given module does not need to be designed, or recompiled, in order to\nrun with a specific version of Redis. For this reason, the module will\nregister to the Redis core using a specific API version. The current API\nversion is \"1\".\n\nThis document is about an alpha version of Redis modules. API, functionalities\nand other details may change in the future."
    },
    {
      "id": "loading-modules",
      "title": "Loading modules",
      "role": "content",
      "text": "In order to test the module you are developing, you can load the module\nusing the following `redis.conf` configuration directive:\n\n    loadmodule /path/to/mymodule.so\n\nIt is also possible to load a module at runtime using the following command:\n\n    MODULE LOAD /path/to/mymodule.so\n\nIn order to list all loaded modules, use:\n\n    MODULE LIST\n\nFinally, you can unload (and later reload if you wish) a module using the\nfollowing command:\n\n    MODULE UNLOAD mymodule\n\nNote that `mymodule` above is not the filename without the `.so` suffix, but\ninstead, the name the module used to register itself into the Redis core.\nThe name can be obtained using [`MODULE LIST`](). However it is good practice\nthat the filename of the dynamic library is the same as the name the module\nuses to register itself into the Redis core."
    },
    {
      "id": "the-simplest-module-you-can-write",
      "title": "The simplest module you can write",
      "role": "content",
      "text": "In order to show the different parts of a module, here we'll show a very\nsimple module that implements a command that outputs a random number.\n\n    #include \"redismodule.h\"\n    #include <stdlib.h>\n\n    int HelloworldRand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {\n        RedisModule_ReplyWithLongLong(ctx,rand());\n        return REDISMODULE_OK;\n    }\n\n    int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {\n        if (RedisModule_Init(ctx,\"helloworld\",1,REDISMODULE_APIVER_1)\n            == REDISMODULE_ERR) return REDISMODULE_ERR;\n\n        if (RedisModule_CreateCommand(ctx,\"helloworld.rand\",\n            HelloworldRand_RedisCommand, \"fast random\",\n            0, 0, 0) == REDISMODULE_ERR)\n            return REDISMODULE_ERR;\n\n        return REDISMODULE_OK;\n    }\n\nThe example module has two functions. One implements a command called\nHELLOWORLD.RAND. This function is specific of that module. However the\nother function called `RedisModule_OnLoad()` must be present in each\nRedis module. It is the entry point for the module to be initialized,\nregister its commands, and potentially other private data structures\nit uses.\n\nNote that it is a good idea for modules to call commands with the\nname of the module followed by a dot, and finally the command name,\nlike in the case of `HELLOWORLD.RAND`. This way it is less likely to\nhave collisions.\n\nNote that if different modules have colliding commands, they'll not be\nable to work in Redis at the same time, since the function\n`RedisModule_CreateCommand` will fail in one of the modules, so the module\nloading will abort returning an error condition."
    },
    {
      "id": "module-initialization",
      "title": "Module initialization",
      "role": "content",
      "text": "The above example shows the usage of the function `RedisModule_Init()`.\nIt should be the first function called by the module `OnLoad` function.\nThe following is the function prototype:\n\n    int RedisModule_Init(RedisModuleCtx *ctx, const char *modulename,\n                         int module_version, int api_version);\n\nThe `Init` function announces the Redis core that the module has a given\nname, its version (that is reported by [`MODULE LIST`]()), and that is willing\nto use a specific version of the API.\n\nIf the API version is wrong, the name is already taken, or there are other\nsimilar errors, the function will return `REDISMODULE_ERR`, and the module\n`OnLoad` function should return ASAP with an error.\n\nBefore the `Init` function is called, no other API function can be called,\notherwise the module will segfault and the Redis instance will crash.\n\nThe second function called, `RedisModule_CreateCommand`, is used in order\nto register commands into the Redis core. The following is the prototype:\n\n    int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name,\n                                  RedisModuleCmdFunc cmdfunc, const char *strflags,\n                                  int firstkey, int lastkey, int keystep);\n\nAs you can see, most Redis modules API calls all take as first argument\nthe `context` of the module, so that they have a reference to the module\ncalling it, to the command and client executing a given command, and so forth.\n\nTo create a new command, the above function needs the context, the command's\nname, a pointer to the function implementing the command, the command's flags\nand the positions of key names in the command's arguments.\n\nThe function that implements the command must have the following prototype:\n\n    int mycommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);\n\nThe command function arguments are just the context, that will be passed\nto all the other API calls, the command argument vector, and total number\nof arguments, as passed by the user.\n\nAs you can see, the arguments are provided as pointers to a specific data\ntype, the `RedisModuleString`. This is an opaque data type you have API\nfunctions to access and use, direct access to its fields is never needed.\n\nZooming into the example command implementation, we can find another call:\n\n    int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long integer);\n\nThis function returns an integer to the client that invoked the command,\nexactly like other Redis commands do, like for example [`INCR`]() or [`SCARD`]()."
    },
    {
      "id": "module-cleanup",
      "title": "Module cleanup",
      "role": "content",
      "text": "In most cases, there is no need for special cleanup.\nWhen a module is unloaded, Redis will automatically unregister commands and\nunsubscribe from notifications.\nHowever in the case where a module contains some persistent memory or\nconfiguration, a module may include an optional `RedisModule_OnUnload`\nfunction.\nIf a module provides this function, it will be invoked during the module unload\nprocess.\nThe following is the function prototype:\n\n    int RedisModule_OnUnload(RedisModuleCtx *ctx);\n\nThe `OnUnload` function may prevent module unloading by returning\n`REDISMODULE_ERR`.\nOtherwise, `REDISMODULE_OK` should be returned."
    },
    {
      "id": "setup-and-dependencies-of-a-redis-module",
      "title": "Setup and dependencies of a Redis module",
      "role": "setup",
      "text": "Redis modules don't depend on Redis or some other library, nor they\nneed to be compiled with a specific `redismodule.h` file. In order\nto create a new module, just copy a recent version of `redismodule.h`\nin your source tree, link all the libraries you want, and create\na dynamic library having the `RedisModule_OnLoad()` function symbol\nexported.\n\nThe module will be able to load into different versions of Redis.\n\nA module can be designed to support both newer and older Redis versions where certain API functions are not available in all versions.\nIf an API function is not implemented in the currently running Redis version, the function pointer is set to NULL.\nThis allows the module to check if a function exists before using it:\n\n    if (RedisModule_SetCommandInfo != NULL) {\n        RedisModule_SetCommandInfo(cmd, &info);\n    }\n\nIn recent versions of `redismodule.h`, a convenience macro `RMAPI_FUNC_SUPPORTED(funcname)` is defined.\nUsing the macro or just comparing with NULL is a matter of personal preference."
    },
    {
      "id": "passing-configuration-parameters-to-redis-modules",
      "title": "Passing configuration parameters to Redis modules",
      "role": "content",
      "text": "When the module is loaded with the [`MODULE LOAD`]() command, or using the\n`loadmodule` directive in the `redis.conf` file, the user is able to pass\nconfiguration parameters to the module by adding arguments after the module\nfile name:\n\n    loadmodule mymodule.so foo bar 1234\n\nIn the above example the strings `foo`, `bar` and `1234` will be passed\nto the module `OnLoad()` function in the `argv` argument as an array\nof RedisModuleString pointers. The number of arguments passed is into `argc`.\n\nThe way you can access those strings will be explained in the rest of this\ndocument. Normally the module will store the module configuration parameters\nin some `static` global variable that can be accessed module wide, so that\nthe configuration can change the behavior of different commands."
    },
    {
      "id": "working-with-redismodulestring-objects",
      "title": "Working with RedisModuleString objects",
      "role": "content",
      "text": "The command argument vector `argv` passed to module commands, and the\nreturn value of other module APIs functions, are of type `RedisModuleString`.\n\nUsually you directly pass module strings to other API calls, however sometimes\nyou may need to directly access the string object.\n\nThere are a few functions in order to work with string objects:\n\n    const char *RedisModule_StringPtrLen(RedisModuleString *string, size_t *len);\n\nThe above function accesses a string by returning its pointer and setting its\nlength in `len`.\nYou should never write to a string object pointer, as you can see from the\n`const` pointer qualifier.\n\nHowever, if you want, you can create new string objects using the following\nAPI:\n\n    RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len);\n\nThe string returned by the above command must be freed using a corresponding\ncall to `RedisModule_FreeString()`:\n\n    void RedisModule_FreeString(RedisModuleString *str);\n\nHowever if you want to avoid having to free strings, the automatic memory\nmanagement, covered later in this document, can be a good alternative, by\ndoing it for you.\n\nNote that the strings provided via the argument vector `argv` never need\nto be freed. You only need to free new strings you create, or new strings\nreturned by other APIs, where it is specified that the returned string must\nbe freed."
    },
    {
      "id": "creating-strings-from-numbers-or-parsing-strings-as-numbers",
      "title": "Creating strings from numbers or parsing strings as numbers",
      "role": "content",
      "text": "Creating a new string from an integer is a very common operation, so there\nis a function to do this:\n\n    RedisModuleString *mystr = RedisModule_CreateStringFromLongLong(ctx,10);\n\nSimilarly in order to parse a string as a number:\n\n    long long myval;\n    if (RedisModule_StringToLongLong(ctx,argv[1],&myval) == REDISMODULE_OK) {\n        /* Do something with 'myval' */\n    }"
    },
    {
      "id": "accessing-redis-keys-from-modules",
      "title": "Accessing Redis keys from modules",
      "role": "content",
      "text": "Most Redis modules, in order to be useful, have to interact with the Redis\ndata space (this is not always true, for example an ID generator may\nnever touch Redis keys). Redis modules have two different APIs in order to\naccess the Redis data space, one is a low level API that provides very\nfast access and a set of functions to manipulate Redis data structures.\nThe other API is more high level, and allows to call Redis commands and\nfetch the result, similarly to how Lua scripts access Redis.\n\nThe high level API is also useful in order to access Redis functionalities\nthat are not available as APIs.\n\nIn general modules developers should prefer the low level API, because commands\nimplemented using the low level API run at a speed comparable to the speed\nof native Redis commands. However there are definitely use cases for the\nhigher level API. For example often the bottleneck could be processing the\ndata and not accessing it.\n\nAlso note that sometimes using the low level API is not harder compared to\nthe higher level one."
    },
    {
      "id": "calling-redis-commands",
      "title": "Calling Redis commands",
      "role": "content",
      "text": "The high level API to access Redis is the sum of the `RedisModule_Call()`\nfunction, together with the functions needed in order to access the\nreply object returned by `Call()`.\n\n`RedisModule_Call` uses a special calling convention, with a format specifier\nthat is used to specify what kind of objects you are passing as arguments\nto the function.\n\nRedis commands are invoked just using a command name and a list of arguments.\nHowever when calling commands, the arguments may originate from different\nkind of strings: null-terminated C strings, RedisModuleString objects as\nreceived from the `argv` parameter in the command implementation, binary\nsafe C buffers with a pointer and a length, and so forth.\n\nFor example if I want to call [`INCRBY`]() using a first argument (the key)\na string received in the argument vector `argv`, which is an array\nof RedisModuleString object pointers, and a C string representing the\nnumber \"10\" as second argument (the increment), I'll use the following\nfunction call:\n\n    RedisModuleCallReply *reply;\n    reply = RedisModule_Call(ctx,\"INCRBY\",\"sc\",argv[1],\"10\");\n\nThe first argument is the context, and the second is always a null terminated\nC string with the command name. The third argument is the format specifier\nwhere each character corresponds to the type of the arguments that will follow.\nIn the above case `\"sc\"` means a RedisModuleString object, and a null\nterminated C string. The other arguments are just the two arguments as\nspecified. In fact `argv[1]` is a RedisModuleString and `\"10\"` is a null\nterminated C string.\n\nThis is the full list of format specifiers:\n\n* **c** -- Null terminated C string pointer.\n* **b** -- C buffer, two arguments needed: C string pointer and `size_t` length.\n* **s** -- RedisModuleString as received in `argv` or by other Redis module APIs returning a RedisModuleString object.\n* **l** -- Long long integer.\n* **v** -- Array of RedisModuleString objects.\n* **!** -- This modifier just tells the function to replicate the command to replicas and AOF. It is ignored from the point of view of arguments parsing.\n* **A** -- This modifier, when `!` is given, tells to suppress AOF propagation: the command will be propagated only to replicas.\n* **R** -- This modifier, when `!` is given, tells to suppress replicas propagation: the command will be propagated only to the AOF if enabled.\n\nThe function returns a `RedisModuleCallReply` object on success, on\nerror NULL is returned.\n\nNULL is returned when the command name is invalid, the format specifier uses\ncharacters that are not recognized, or when the command is called with the\nwrong number of arguments. In the above cases the `errno` var is set to `EINVAL`. NULL is also returned when, in an instance with Cluster enabled, the target\nkeys are about non local hash slots. In this case `errno` is set to `EPERM`."
    },
    {
      "id": "working-with-redismodulecallreply-objects",
      "title": "Working with RedisModuleCallReply objects.",
      "role": "content",
      "text": "`RedisModuleCall` returns reply objects that can be accessed using the\n`RedisModule_CallReply*` family of functions.\n\nIn order to obtain the type or reply (corresponding to one of the data types\nsupported by the Redis protocol), the function `RedisModule_CallReplyType()`\nis used:\n\n    reply = RedisModule_Call(ctx,\"INCRBY\",\"sc\",argv[1],\"10\");\n    if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_INTEGER) {\n        long long myval = RedisModule_CallReplyInteger(reply);\n        /* Do something with myval. */\n    }\n\nValid reply types are:\n\n* `REDISMODULE_REPLY_STRING` Bulk string or status replies.\n* `REDISMODULE_REPLY_ERROR` Errors.\n* `REDISMODULE_REPLY_INTEGER` Signed 64 bit integers.\n* `REDISMODULE_REPLY_ARRAY` Array of replies.\n* `REDISMODULE_REPLY_NULL` NULL reply.\n\nStrings, errors and arrays have an associated length. For strings and errors\nthe length corresponds to the length of the string. For arrays the length\nis the number of elements. To obtain the reply length the following function\nis used:\n\n    size_t reply_len = RedisModule_CallReplyLength(reply);\n\nIn order to obtain the value of an integer reply, the following function is used, as already shown in the example above:\n\n    long long reply_integer_val = RedisModule_CallReplyInteger(reply);\n\nCalled with a reply object of the wrong type, the above function always\nreturns `LLONG_MIN`.\n\nSub elements of array replies are accessed this way:\n\n    RedisModuleCallReply *subreply;\n    subreply = RedisModule_CallReplyArrayElement(reply,idx);\n\nThe above function returns NULL if you try to access out of range elements.\n\nStrings and errors (which are like strings but with a different type) can\nbe accessed using in the following way, making sure to never write to\nthe resulting pointer (that is returned as a `const` pointer so that\nmisusing must be pretty explicit):\n\n    size_t len;\n    char *ptr = RedisModule_CallReplyStringPtr(reply,&len);\n\nIf the reply type is not a string or an error, NULL is returned.\n\nRedisCallReply objects are not the same as module string objects\n(RedisModuleString types). However sometimes you may need to pass replies\nof type string or integer, to API functions expecting a module string.\n\nWhen this is the case, you may want to evaluate if using the low level\nAPI could be a simpler way to implement your command, or you can use\nthe following function in order to create a new string object from a\ncall reply of type string, error or integer:\n\n    RedisModuleString *mystr = RedisModule_CreateStringFromCallReply(myreply);\n\nIf the reply is not of the right type, NULL is returned.\nThe returned string object should be released with `RedisModule_FreeString()`\nas usually, or by enabling automatic memory management (see corresponding\nsection)."
    },
    {
      "id": "releasing-call-reply-objects",
      "title": "Releasing call reply objects",
      "role": "content",
      "text": "Reply objects must be freed using `RedisModule_FreeCallReply`. For arrays,\nyou need to free only the top level reply, not the nested replies.\nCurrently the module implementation provides a protection in order to avoid\ncrashing if you free a nested reply object for error, however this feature\nis not guaranteed to be here forever, so should not be considered part\nof the API.\n\nIf you use automatic memory management (explained later in this document)\nyou don't need to free replies (but you still could if you wish to release\nmemory ASAP)."
    },
    {
      "id": "returning-values-from-redis-commands",
      "title": "Returning values from Redis commands",
      "role": "returns",
      "text": "Like normal Redis commands, new commands implemented via modules must be\nable to return values to the caller. The API exports a set of functions for\nthis goal, in order to return the usual types of the Redis protocol, and\narrays of such types as elements. Also errors can be returned with any\nerror string and code (the error code is the initial uppercase letters in\nthe error message, like the \"BUSY\" string in the \"BUSY the sever is busy\" error\nmessage).\n\nAll the functions to send a reply to the client are called\n`RedisModule_ReplyWith<something>`.\n\nTo return an error, use:\n\n    RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err);\n\nThere is a predefined error string for key of wrong type errors:\n\n    REDISMODULE_ERRORMSG_WRONGTYPE\n\nExample usage:\n\n    RedisModule_ReplyWithError(ctx,\"ERR invalid arguments\");\n\nWe already saw how to reply with a `long long` in the examples above:\n\n    RedisModule_ReplyWithLongLong(ctx,12345);\n\nTo reply with a simple string, that can't contain binary values or newlines,\n(so it's suitable to send small words, like \"OK\") we use:\n\n    RedisModule_ReplyWithSimpleString(ctx,\"OK\");\n\nIt's possible to reply with \"bulk strings\" that are binary safe, using\ntwo different functions:\n\n    int RedisModule_ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len);\n\n    int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str);\n\nThe first function gets a C pointer and length. The second a RedisModuleString\nobject. Use one or the other depending on the source type you have at hand.\n\nIn order to reply with an array, you just need to use a function to emit the\narray length, followed by as many calls to the above functions as the number\nof elements of the array are:\n\n    RedisModule_ReplyWithArray(ctx,2);\n    RedisModule_ReplyWithStringBuffer(ctx,\"age\",3);\n    RedisModule_ReplyWithLongLong(ctx,22);\n\nTo return nested arrays is easy, your nested array element just uses another\ncall to `RedisModule_ReplyWithArray()` followed by the calls to emit the\nsub array elements."
    },
    {
      "id": "returning-arrays-with-dynamic-length",
      "title": "Returning arrays with dynamic length",
      "role": "returns",
      "text": "Sometimes it is not possible to know beforehand the number of items of\nan array. As an example, think of a Redis module implementing a FACTOR\ncommand that given a number outputs the prime factors. Instead of\nfactorializing the number, storing the prime factors into an array, and\nlater produce the command reply, a better solution is to start an array\nreply where the length is not known, and set it later. This is accomplished\nwith a special argument to `RedisModule_ReplyWithArray()`:\n\n    RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN);\n\nThe above call starts an array reply so we can use other `ReplyWith` calls\nin order to produce the array items. Finally in order to set the length,\nuse the following call:\n\n    RedisModule_ReplySetArrayLength(ctx, number_of_items);\n\nIn the case of the FACTOR command, this translates to some code similar\nto this:\n\n    RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN);\n    number_of_factors = 0;\n    while(still_factors) {\n        RedisModule_ReplyWithLongLong(ctx, some_factor);\n        number_of_factors++;\n    }\n    RedisModule_ReplySetArrayLength(ctx, number_of_factors);\n\nAnother common use case for this feature is iterating over the arrays of\nsome collection and only returning the ones passing some kind of filtering.\n\nIt is possible to have multiple nested arrays with postponed reply.\nEach call to `SetArray()` will set the length of the latest corresponding\ncall to `ReplyWithArray()`:\n\n    RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN);\n    ... generate 100 elements ...\n    RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN);\n    ... generate 10 elements ...\n    RedisModule_ReplySetArrayLength(ctx, 10);\n    RedisModule_ReplySetArrayLength(ctx, 100);\n\nThis creates a 100 items array having as last element a 10 items array."
    },
    {
      "id": "arity-and-type-checks",
      "title": "Arity and type checks",
      "role": "content",
      "text": "Often commands need to check that the number of arguments and type of the key\nis correct. In order to report a wrong arity, there is a specific function\ncalled `RedisModule_WrongArity()`. The usage is trivial:\n\n    if (argc != 2) return RedisModule_WrongArity(ctx);\n\nChecking for the wrong type involves opening the key and checking the type:\n\n    RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],\n        REDISMODULE_READ|REDISMODULE_WRITE);\n\n    int keytype = RedisModule_KeyType(key);\n    if (keytype != REDISMODULE_KEYTYPE_STRING &&\n        keytype != REDISMODULE_KEYTYPE_EMPTY)\n    {\n        RedisModule_CloseKey(key);\n        return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);\n    }\n\nNote that you often want to proceed with a command both if the key\nis of the expected type, or if it's empty."
    },
    {
      "id": "low-level-access-to-keys",
      "title": "Low level access to keys",
      "role": "content",
      "text": "Low level access to keys allow to perform operations on value objects associated\nto keys directly, with a speed similar to what Redis uses internally to\nimplement the built-in commands.\n\nOnce a key is opened, a key pointer is returned that will be used with all the\nother low level API calls in order to perform operations on the key or its\nassociated value.\n\nBecause the API is meant to be very fast, it cannot do too many run-time\nchecks, so the user must be aware of certain rules to follow:\n\n* Opening the same key multiple times where at least one instance is opened for writing, is undefined and may lead to crashes.\n* While a key is open, it should only be accessed via the low level key API. For example opening a key, then calling DEL on the same key using the `RedisModule_Call()` API will result into a crash. However it is safe to open a key, perform some operation with the low level API, closing it, then using other APIs to manage the same key, and later opening it again to do some more work.\n\nIn order to open a key the `RedisModule_OpenKey` function is used. It returns\na key pointer, that we'll use with all the next calls to access and modify\nthe value:\n\n    RedisModuleKey *key;\n    key = RedisModule_OpenKey(ctx,argv[1],REDISMODULE_READ);\n\nThe second argument is the key name, that must be a `RedisModuleString` object.\nThe third argument is the mode: `REDISMODULE_READ` or `REDISMODULE_WRITE`.\nIt is possible to use `|` to bitwise OR the two modes to open the key in\nboth modes. Currently a key opened for writing can also be accessed for reading\nbut this is to be considered an implementation detail. The right mode should\nbe used in sane modules.\n\nYou can open non existing keys for writing, since the keys will be created\nwhen an attempt to write to the key is performed. However when opening keys\njust for reading, `RedisModule_OpenKey` will return NULL if the key does not\nexist.\n\nOnce you are done using a key, you can close it with:\n\n    RedisModule_CloseKey(key);\n\nNote that if automatic memory management is enabled, you are not forced to\nclose keys. When the module function returns, Redis will take care to close\nall the keys which are still open."
    },
    {
      "id": "getting-the-key-type",
      "title": "Getting the key type",
      "role": "content",
      "text": "In order to obtain the value of a key, use the `RedisModule_KeyType()` function:\n\n    int keytype = RedisModule_KeyType(key);\n\nIt returns one of the following values:\n\n    REDISMODULE_KEYTYPE_EMPTY\n    REDISMODULE_KEYTYPE_STRING\n    REDISMODULE_KEYTYPE_LIST\n    REDISMODULE_KEYTYPE_HASH\n    REDISMODULE_KEYTYPE_SET\n    REDISMODULE_KEYTYPE_ZSET\n\nThe above are just the usual Redis key types, with the addition of an empty\ntype, that signals the key pointer is associated with an empty key that\ndoes not yet exists."
    },
    {
      "id": "creating-new-keys",
      "title": "Creating new keys",
      "role": "content",
      "text": "To create a new key, open it for writing and then write to it using one\nof the key writing functions. Example:\n\n    RedisModuleKey *key;\n    key = RedisModule_OpenKey(ctx,argv[1],REDISMODULE_WRITE);\n    if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) {\n        RedisModule_StringSet(key,argv[2]);\n    }"
    },
    {
      "id": "deleting-keys",
      "title": "Deleting keys",
      "role": "content",
      "text": "Just use:\n\n    RedisModule_DeleteKey(key);\n\nThe function returns `REDISMODULE_ERR` if the key is not open for writing.\nNote that after a key gets deleted, it is setup in order to be targeted\nby new key commands. For example `RedisModule_KeyType()` will return it is\nan empty key, and writing to it will create a new key, possibly of another\ntype (depending on the API used)."
    },
    {
      "id": "managing-key-expires-ttls",
      "title": "Managing key expires (TTLs)",
      "role": "content",
      "text": "To control key expires two functions are provided, that are able to set,\nmodify, get, and unset the time to live associated with a key.\n\nOne function is used in order to query the current expire of an open key:\n\n    mstime_t RedisModule_GetExpire(RedisModuleKey *key);\n\nThe function returns the time to live of the key in milliseconds, or\n`REDISMODULE_NO_EXPIRE` as a special value to signal the key has no associated\nexpire or does not exist at all (you can differentiate the two cases checking\nif the key type is `REDISMODULE_KEYTYPE_EMPTY`).\n\nIn order to change the expire of a key the following function is used instead:\n\n    int RedisModule_SetExpire(RedisModuleKey *key, mstime_t expire);\n\nWhen called on a non existing key, `REDISMODULE_ERR` is returned, because\nthe function can only associate expires to existing open keys (non existing\nopen keys are only useful in order to create new values with data type\nspecific write operations).\n\nAgain the `expire` time is specified in milliseconds. If the key has currently\nno expire, a new expire is set. If the key already have an expire, it is\nreplaced with the new value.\n\nIf the key has an expire, and the special value `REDISMODULE_NO_EXPIRE` is\nused as a new expire, the expire is removed, similarly to the Redis\n[`PERSIST`]() command. In case the key was already persistent, no operation is\nperformed."
    },
    {
      "id": "obtaining-the-length-of-values",
      "title": "Obtaining the length of values",
      "role": "content",
      "text": "There is a single function in order to retrieve the length of the value\nassociated to an open key. The returned length is value-specific, and is\nthe string length for strings, and the number of elements for the aggregated\ndata types (how many elements there is in a list, set, sorted set, hash).\n\n    size_t len = RedisModule_ValueLength(key);\n\nIf the key does not exist, 0 is returned by the function:"
    },
    {
      "id": "string-type-api",
      "title": "String type API",
      "role": "content",
      "text": "Setting a new string value, like the Redis [`SET`]() command does, is performed\nusing:\n\n    int RedisModule_StringSet(RedisModuleKey *key, RedisModuleString *str);\n\nThe function works exactly like the Redis [`SET`]() command itself, that is, if\nthere is a prior value (of any type) it will be deleted.\n\nAccessing existing string values is performed using DMA (direct memory\naccess) for speed. The API will return a pointer and a length, so that's\npossible to access and, if needed, modify the string directly.\n\n    size_t len, j;\n    char *myptr = RedisModule_StringDMA(key,&len,REDISMODULE_WRITE);\n    for (j = 0; j < len; j++) myptr[j] = 'A';\n\nIn the above example we write directly on the string. Note that if you want\nto write, you must be sure to ask for `WRITE` mode.\n\nDMA pointers are only valid if no other operations are performed with the key\nbefore using the pointer, after the DMA call.\n\nSometimes when we want to manipulate strings directly, we need to change\ntheir size as well. For this scope, the `RedisModule_StringTruncate` function\nis used. Example:\n\n    RedisModule_StringTruncate(mykey,1024);\n\nThe function truncates, or enlarges the string as needed, padding it with\nzero bytes if the previous length is smaller than the new length we request.\nIf the string does not exist since `key` is associated to an open empty key,\na string value is created and associated to the key.\n\nNote that every time `StringTruncate()` is called, we need to re-obtain\nthe DMA pointer again, since the old may be invalid."
    },
    {
      "id": "list-type-api",
      "title": "List type API",
      "role": "content",
      "text": "It's possible to push and pop values from list values:\n\n    int RedisModule_ListPush(RedisModuleKey *key, int where, RedisModuleString *ele);\n    RedisModuleString *RedisModule_ListPop(RedisModuleKey *key, int where);\n\nIn both the APIs the `where` argument specifies if to push or pop from tail\nor head, using the following macros:\n\n    REDISMODULE_LIST_HEAD\n    REDISMODULE_LIST_TAIL\n\nElements returned by `RedisModule_ListPop()` are like strings created with\n`RedisModule_CreateString()`, they must be released with\n`RedisModule_FreeString()` or by enabling automatic memory management."
    },
    {
      "id": "set-type-api",
      "title": "Set type API",
      "role": "content",
      "text": "Work in progress."
    },
    {
      "id": "sorted-set-type-api",
      "title": "Sorted set type API",
      "role": "content",
      "text": "Documentation missing, please refer to the top comments inside `module.c`\nfor the following functions:\n\n* `RedisModule_ZsetAdd`\n* `RedisModule_ZsetIncrby`\n* `RedisModule_ZsetScore`\n* `RedisModule_ZsetRem`\n\nAnd for the sorted set iterator:\n\n* `RedisModule_ZsetRangeStop`\n* `RedisModule_ZsetFirstInScoreRange`\n* `RedisModule_ZsetLastInScoreRange`\n* `RedisModule_ZsetFirstInLexRange`\n* `RedisModule_ZsetLastInLexRange`\n* `RedisModule_ZsetRangeCurrentElement`\n* `RedisModule_ZsetRangeNext`\n* `RedisModule_ZsetRangePrev`\n* `RedisModule_ZsetRangeEndReached`"
    },
    {
      "id": "hash-type-api",
      "title": "Hash type API",
      "role": "content",
      "text": "Documentation missing, please refer to the top comments inside `module.c`\nfor the following functions:\n\n* `RedisModule_HashSet`\n* `RedisModule_HashGet`"
    },
    {
      "id": "iterating-aggregated-values",
      "title": "Iterating aggregated values",
      "role": "content",
      "text": "Work in progress."
    },
    {
      "id": "replicating-commands",
      "title": "Replicating commands",
      "role": "content",
      "text": "If you want to use module commands exactly like normal Redis commands, in the\ncontext of replicated Redis instances, or using the AOF file for persistence,\nit is important for module commands to handle their replication in a consistent\nway.\n\nWhen using the higher level APIs to invoke commands, replication happens\nautomatically if you use the \"!\" modifier in the format string of\n`RedisModule_Call()` as in the following example:\n\n    reply = RedisModule_Call(ctx,\"INCRBY\",\"!sc\",argv[1],\"10\");\n\nAs you can see the format specifier is `\"!sc\"`. The bang is not parsed as a\nformat specifier, but it internally flags the command as \"must replicate\".\n\nIf you use the above programming style, there are no problems.\nHowever sometimes things are more complex than that, and you use the low level\nAPI. In this case, if there are no side effects in the command execution, and\nit consistently always performs the same work, what is possible to do is to\nreplicate the command verbatim as the user executed it. To do that, you just\nneed to call the following function:\n\n    RedisModule_ReplicateVerbatim(ctx);\n\nWhen you use the above API, you should not use any other replication function\nsince they are not guaranteed to mix well.\n\nHowever this is not the only option. It's also possible to exactly tell\nRedis what commands to replicate as the effect of the command execution, using\nan API similar to `RedisModule_Call()` but that instead of calling the command\nsends it to the AOF / replicas stream. Example:\n\n    RedisModule_Replicate(ctx,\"INCRBY\",\"cl\",\"foo\",my_increment);\n\nIt's possible to call `RedisModule_Replicate` multiple times, and each\nwill emit a command. All the sequence emitted is wrapped between a\n`MULTI/EXEC` transaction, so that the AOF and replication effects are the\nsame as executing a single command.\n\nNote that before Redis version 7.0, `Call()` replication and `Replicate()` replication have a rule,\nin case you want to mix both forms of replication (not necessarily a good\nidea if there are simpler approaches). Commands replicated with `Call()`\nare always the first emitted in the final `MULTI/EXEC` block, while all\nthe commands emitted with `Replicate()` will follow."
    },
    {
      "id": "automatic-memory-management",
      "title": "Automatic memory management",
      "role": "content",
      "text": "Normally when writing programs in the C language, programmers need to manage\nmemory manually. This is why the Redis modules API has functions to release\nstrings, close open keys, free replies, and so forth.\n\nHowever given that commands are executed in a contained environment and\nwith a set of strict APIs, Redis is able to provide automatic memory management\nto modules, at the cost of some performance (most of the time, a very low\ncost).\n\nWhen automatic memory management is enabled:\n\n1. You don't need to close open keys.\n2. You don't need to free replies.\n3. You don't need to free RedisModuleString objects.\n\nHowever you can still do it, if you want. For example, automatic memory\nmanagement may be active, but inside a loop allocating a lot of strings,\nyou may still want to free strings no longer used.\n\nIn order to enable automatic memory management, just call the following\nfunction at the start of the command implementation:\n\n    RedisModule_AutoMemory(ctx);\n\nAutomatic memory management is usually the way to go, however experienced\nC programmers may not use it in order to gain some speed and memory usage\nbenefit."
    },
    {
      "id": "allocating-memory-into-modules",
      "title": "Allocating memory into modules",
      "role": "content",
      "text": "Normal C programs use `malloc()` and `free()` in order to allocate and\nrelease memory dynamically. While in Redis modules the use of malloc is\nnot technically forbidden, it is a lot better to use the Redis Modules\nspecific functions, that are exact replacements for `malloc`, `free`,\n`realloc` and `strdup`. These functions are:\n\n    void *RedisModule_Alloc(size_t bytes);\n    void* RedisModule_Realloc(void *ptr, size_t bytes);\n    void RedisModule_Free(void *ptr);\n    void RedisModule_Calloc(size_t nmemb, size_t size);\n    char *RedisModule_Strdup(const char *str);\n\nThey work exactly like their `libc` equivalent calls, however they use\nthe same allocator Redis uses, and the memory allocated using these\nfunctions is reported by the [`INFO`]() command in the memory section, is\naccounted when enforcing the `maxmemory` policy, and in general is\na first citizen of the Redis executable. On the contrary, the method\nallocated inside modules with libc `malloc()` is transparent to Redis.\n\nAnother reason to use the modules functions in order to allocate memory\nis that, when creating native data types inside modules, the RDB loading\nfunctions can return deserialized strings (from the RDB file) directly\nas `RedisModule_Alloc()` allocations, so they can be used directly to\npopulate data structures after loading, instead of having to copy them\nto the data structure."
    },
    {
      "id": "pool-allocator",
      "title": "Pool allocator",
      "role": "content",
      "text": "Sometimes in commands implementations, it is required to perform many\nsmall allocations that will be not retained at the end of the command\nexecution, but are just functional to execute the command itself.\n\nThis work can be more easily accomplished using the Redis pool allocator:\n\n    void *RedisModule_PoolAlloc(RedisModuleCtx *ctx, size_t bytes);\n\nIt works similarly to `malloc()`, and returns memory aligned to the\nnext power of two of greater or equal to `bytes` (for a maximum alignment\nof 8 bytes). However it allocates memory in blocks, so it the overhead\nof the allocations is small, and more important, the memory allocated\nis automatically released when the command returns.\n\nSo in general short living allocations are a good candidates for the pool\nallocator."
    },
    {
      "id": "writing-commands-compatible-with-redis-cluster",
      "title": "Writing commands compatible with Redis Cluster",
      "role": "content",
      "text": "Documentation missing, please check the following functions inside `module.c`:\n\n    RedisModule_IsKeysPositionRequest(ctx);\n    RedisModule_KeyAtPos(ctx,pos);"
    }
  ],
  "examples": []
}
