WebAssembly User-Defined Functions

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/sql-reference/functions/wasm_udf.md)

ClickHouse supports creating user-defined functions (UDFs) written in WebAssembly. This allows you to execute custom logic written in languages like Rust, C, C++, or others by compiling them to WebAssembly modules.

Not supported in ClickHouse Cloud

Experimental feature. [Learn more.](/docs/beta-and-experimental-features#experimental-features)

## Overview[​](#overview "Direct link to Overview")

A WebAssembly module is a compiled binary file that contains one or more functions that can be called from ClickHouse.
Think of a module as a library or shared object that you load once and reuse many times.

WebAssembly module containing UDFs can be written in any language that can compile to WebAssembly, such as Rust, C, or C++.

Code compiled to WebAssembly ("guest" code) and executed by ClickHouse ("host") run in a sandboxed environment having access only to a dedicated memory space.

Guest code exports functions that ClickHouse can invoke - these include the functions that implement your custom logic (used to define UDFs) as well as support functions required for memory management and data exchange between ClickHouse and the WebAssembly code.

Your code should be compiled to "freestanding" WebAssembly (aka `wasm32-unknown-unknown`) without any dependencies on an operating system or standard library. Also only default 32-bit WebAssembly target is supported (no `wasm64` extension).
The module must follow one of the supported communication protocols (ABIs) for interacting with ClickHouse.

Once compiled, the module's binary code is loaded into ClickHouse by inserting it into the `system.webassembly_modules` table.
After that, you can create UDFs that reference functions exported by the module using the `CREATE FUNCTION ... LANGUAGE WASM` statement.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

Enable WebAssembly support in your ClickHouse configuration:

```
<clickhouse>
    <allow_experimental_webassembly_udf>true</allow_experimental_webassembly_udf>
    <webassembly_udf_engine>wasmtime</webassembly_udf_engine>
</clickhouse>
```

Available Engine Implementations:

- `wasmtime` (default, recommended) — uses [WasmTime](https://github.com/bytecodealliance/wasmtime)
- `wasmedge` — uses [WasmEdge](https://github.com/WasmEdge/WasmEdge)

## Quick Start[​](#quick-start "Direct link to Quick Start")

This example demonstrates the complete workflow of creating a WebAssembly UDF by implementing the [Collatz conjecture](https://en.wikipedia.org/wiki/Collatz_conjecture) calculator.

We'll write the code in WebAssembly Text format (WAT), which is a human-readable representation of WebAssembly, so no any programming language is required at this stage.
ClickHouse requires the module to be in binary format, so we'll use the transpiler to convert WAT to WASM.
To perform this conversion you may use `wat2wasm` from the [WebAssembly Binary Toolkit (WABT)](https://github.com/WebAssembly/wabt) or `parse` command from the [wasm-tools](https://github.com/bytecodealliance/wasm-tools).

```
cat << 'EOF' | wasm-tools parse | clickhouse client -q "INSERT INTO system.webassembly_modules (name, code) SELECT 'collatz', code FROM input('code String') FORMAT RawBlob"
(module
  (func $next (param $n i32) (result i32)
    local.get $n i32.const 1 i32.and
    (if (result i32)
      (then local.get $n i32.const 3 i32.mul i32.const 1 i32.add)
      (else local.get $n i32.const 2 i32.div_u)))
  (func $steps (export "steps") (param $n i32) (result i32)
    (local $count i32)
    local.get $n i32.const 1 i32.lt_u
    (if (then i32.const 0 return))
    (block $done (loop $loop
      local.get $n i32.const 1 i32.eq br_if $done
      local.get $n call $next local.set $n
      local.get $count i32.const 1 i32.add local.set $count
      br $loop))
    local.get $count)
)
EOF
```

In snippet above we pipe binary WASM code directly into ClickHouse client using `FORMAT RawBlob` to insert it into `system.webassembly_modules` table.

Then we define the UDF that references the `steps` function exported by the module:

```
CREATE FUNCTION collatz_steps LANGUAGE WASM ARGUMENTS (n UInt32) RETURNS UInt32 FROM 'collatz' :: 'steps';
```

Note that we specify function name from the module after `::`, because it differs from the UDF name.

Now we can use the `collatz_steps` function in our queries:

```
SELECT groupArray(collatz_steps(number :: UInt32))
FROM numbers(1, 100)
FORMAT TSV
```

The `number` column is explicitly cast to `UInt32`, because WebAssembly functions expect exact type matches specified signature in `CREATE FUNCTION` statement.

In the result we got sequence of Collatz steps for numbers from 1 to 100, corresponding to sequence [A006577 from the OEIS](https://oeis.org/A006577).

```
[0,1,7,2,5,8,16,3,19,6,14,9,9,17,17,4,12,20,20,7,7,15,15,10,23,10,111,18,18,18,106,5,26,13,13,21,21,21,34,8,109,8,29,16,16,16,104,11,24,24,24,11,11,112,112,19,32,19,32,19,19,107,107,6,27,27,27,14,14,14,102,22,115,22,14,22,22,35,35,9,22,110,110,9,9,30,30,17,30,17,92,17,17,105,105,12,118,25,25,25]
```

## Manage WASM modules via system table[​](#manage-wasm-modules-via-system-table "Direct link to Manage WASM modules via system table")

WebAssembly modules are stored in the `system.webassembly_modules` table having the following structure:

- **Columns**
  - `name` String — Module name. Non-empty, word characters only.
  - `code` String — Raw binary WASM code. Write-only, reads return empty string.
  - `hash` UInt256 — SHA256 of the module binary (zero if present on disk but not yet loaded).

Module management happens through standard SQL operations on this table:

### Insert a module[​](#insert-a-module "Direct link to Insert a module")

```
INSERT INTO system.webassembly_modules (name, code)
SELECT 'my_module', base64Decode('AGFzbQEAAAA...');
```

Optionally, provide integrity hash:

```
INSERT INTO system.webassembly_modules (name, code, hash)
SELECT 'my_module', base64Decode('...'), reinterpretAsUInt256(unhex('369f...c57d'));
```

If the provided hash does not match the computed SHA256 of the module code, the insertion fails. It may be useful when loading modules from external sources such as S3 or HTTP.

### List modules[​](#list-modules "Direct link to List modules")

```
SELECT name, lower(hex(reinterpretAsFixedString(hash))) AS sha256 FROM system.webassembly_modules

   ┌─name────┬─sha256───────────────────────────────────────────────────────────┐
1. │ collatz │ a084a10b7b5cb07db198bc93bf1f3c1f8cb8ef279df7a4f6b66b1cdd55d79c48 │
   └─────────┴──────────────────────────────────────────────────────────────────┘
```

### Delete a module[​](#delete-a-module "Direct link to Delete a module")

Deletion performed by `DELETE FROM system.webassembly_modules WHERE name = '...'` statement.
Only deletion of single module by exact name per single statement is supported.

```
DELETE FROM system.webassembly_modules WHERE name = 'collatz';
```

If any existing UDFs reference the module, the deletion fails, so you must drop those UDFs first.

## Create a WebAssembly UDF[​](#create-a-webassembly-udf "Direct link to Create a WebAssembly UDF")

**Syntax**:

```
CREATE [OR REPLACE] FUNCTION function_name
LANGUAGE WASM
FROM 'module_name' [:: 'source_function_name']
ARGUMENTS ( [name type[, ...]] | [type[, ...]] )
RETURNS return_type
[ABI ROW_DIRECT | ABI BUFFERED_V1]
[SHA256_HASH 'hex']
[SETTINGS key = value[, ...]];
```

**Parameters**: