--- title: "Developing UDF Modules" description: "Learn how to develop, register, and use Lua and C-based UDF modules in the Aerospike database." --- # Developing UDF Modules > For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt) > > All documentation pages available in markdown. ## Modules Written in Lua A Lua [`module`](https://www.lua.org/manual/5.1/manual.html#5.3) is a collection of variables and functions contained in a single file. Modules can be imported and used by other Lua modules, including UDFs. A module name must not conflict with other Lua objects pre-registered by the Aerospike server. The following module names should be avoided: - aerospike - bytes - geojson - iterator - list - map - record - stream ### Module filename rules Available in Aerospike Database 8.1.2.2, 8.0.0.17, 7.2.0.19, 7.1.0.25 and later. UDF module names must conform to a fixed allowlist. See [UDF security and sandbox hardening](https://aerospike.com/docs/database/advanced/udf/security) for the rules and migration guidance for entries that fail validation after upgrade. ### Sandbox modes Aerospike runs every UDF in an embedded Lua state. The set of Lua libraries available to UDFs depends on the [`mod-lua.allow-unsafe-lua`](https://aerospike.com/docs/database/reference/config#mod-lua__allow-unsafe-lua) configuration option. **Default mode (`allow-unsafe-lua=true`):** The following restrictions apply. - The Lua `io` library is not available. - The Lua `os` library is restricted to `os.clock()`, `os.date()`, `os.difftime()`, and `os.time()`. - The Lua `debug` library is not available. - `os.exit()` is not available. **Hardened mode (`allow-unsafe-lua=false`):** Hardened mode replaces the default sandbox with stricter restrictions: - The `os`, `io`, `debug`, `dofile`, `loadfile`, `load`, and `loadstring` globals are removed entirely. The four `os.*` functions allowed in default mode are **not** available in hardened mode. - `package.searchpath`, `package.loadlib`, and `package.cpath` are removed. - Native `.so` UDF modules cannot be registered. See [Using C functions in UDF Modules](#using-c-functions-in-udf-modules) later on this page. - Precompiled Lua bytecode UDFs are rejected at registration with a compile error; the server loads Lua chunks in text-only mode. - The `.lua` extension is checked case-sensitively at registration. See [UDF security and sandbox hardening](https://aerospike.com/docs/database/advanced/udf/security) for the full set of changes and a migration checklist. ### Creating a Module In the following example, we define a local table `exports` in the file _mymodule.lua_. This module will be populated with the functions to be exported. ```lua local exports = {} function exports.hello() return "Hello " end function exports.world() return "World!" end return exports ``` ### Registering a Module Lua Modules must be registered with the Aerospike Server. To install your modules, you may - Use the [aql](https://aerospike.com/docs/database/tools/aql) - Use the [asadm](https://aerospike.com/docs/database/tools/asadm) tool - Use any of the Aerospike Clients To register the module using asadm: Terminal window ```bash Admin> enable Admin+> manage udfs add mymodule.lua path path/to/mymodule.lua Successfully added UDF mymodule.lua Admin+> Admin+> show udfs ~~~~~~~~~~UDF Modules (2021-01-23 02:00:18 UTC)~~~~~~~~~~~ Filename| Hash|Type mymodule.lua|7fae110826972135a3c3b8a812d43243e7c7a23c|LUA Number of rows: 1 ``` To register the module using aql: Terminal window ```bash aql> register module 'mymodule.lua' OK, 1 module added. aql> show modules +-----------------+--------------------------------------------+-------+ | filename | hash | type | +-----------------+--------------------------------------------+-------+ | "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" | +-----------------+--------------------------------------------+-------+ ``` Another module can now `require` _mymodule.lua_ into a local variable and use it. ### Example: A Hello World UDF In a file _example.lua_ ```lua local mm = require('mymodule') function helloworld(rec) return mm.hello() .. mm.world() end ``` In aql Terminal window ```bash aql> register module 'example.lua' OK, 1 module added. aql> show modules +-----------------+--------------------------------------------+-------+ | filename | hash | type | +-----------------+--------------------------------------------+-------+ | "example.lua" | "c42bf3f4a6f8f727efcfb884c97ee894764f1dc7" | "LUA" | | "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" | +-----------------+--------------------------------------------+-------+ 2 rows in set (0.002 secs) aql> insert into test.foo (PK, x) values ('1', 24) OK, 1 record affected. aql> execute example.helloworld() on test.foo where PK='1' +----------------+ | helloworld | +----------------+ | "Hello World!" | +----------------+ 1 row in set (0.001 secs) ``` ## Using C functions in UDF Modules Aerospike UDFs written in Lua can call C functions from shared objects. For more information read about the [C API for Lua](https://www.lua.org/manual/5.1/manual.html#3). ::: note Make sure you compile the module to be loaded into Aerospike using the correct version of Lua. ::: ::: caution Native `.so` UDF modules are only available when [`mod-lua.allow-unsafe-lua`](https://aerospike.com/docs/database/reference/config#mod-lua__allow-unsafe-lua) is `true` (the default). Setting it to `false` rejects registration of `.so` modules. See [UDF security and sandbox hardening](https://aerospike.com/docs/database/advanced/udf/security). ::: ### Example: Compiling and Registering a Shared Object In this example the file _power.c_ contains sample C code: ```c #include #include #include static int go(lua_State * L) { int rtrn = lua_tonumber(L, -1); /* Get the single number arg */ lua_pushnumber(L,rtrn*rtrn); /* square it and push the return */ return 1; } static const struct luaL_reg golib [] = { {"go", go}, {NULL, NULL} }; int luaopen_power(lua_State * L) { luaL_openlib(L, "go", golib, 0); return 1; } ``` The Lua UDF module _use.lua_ requires and calls the _power.so_ shared object ```lua function thepower(rec, basenum) local power = require("power") local rtn = power.go(basenum); --info(rtn) return rtn end ``` ### Get the Lua Source Download the [Lua 5.1.4 library](https://sourceforge.net/projects/luabinaries/files/5.1.4/Linux%20Libraries/) to allow for the necessary Lua code to be linked. ### Compile ```plaintext gcc -fPIC -o power.so -shared power.c -I /usr/include/ ``` ### Register and Execute In aql: Terminal window ```bash aql> register module 'power.so' OK, 1 module added. aql> register module 'use.lua' OK, 1 module added. aql> show modules +-----------------+--------------------------------------------+-------+ | filename | hash | type | +-----------------+--------------------------------------------+-------+ | "example.lua" | "c42bf3f4a6f8f727efcfb884c97ee894764f1dc7" | "LUA" | | "power.so" | "99703e01482f065c62f0d0c55ba6b1f3214e3601" | "LUA" | | "use.lua" | "5093704498b333e57d7dd033b529c4b4e0d99edb" | "LUA" | | "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" | +-----------------+--------------------------------------------+-------+ 4 rows in set (0.002 secs) aql> execute use.thepower(4) on test.foo where PK='1' +----------+ | thepower | +----------+ | 16 | +----------+ 1 row in set (0.001 secs) ```