---
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/8.1.2/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/8.1.2/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/8.1.2/advanced/udf/security).
:::

### Example: Compiling and Registering a Shared Object

In this example the file _power.c_ contains sample C code:

```c
#include <lua.h>

#include <lauxlib.h>

#include <lualib.h>

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)
```