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