> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8a08bda2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Documentation for WebAssembly User Defined Functions

# WebAssembly User-Defined Functions

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            Experimental feature. <u><a href="/docs/beta-and-experimental-features#experimental-features">Learn more.</a></u>
        </div>;
};

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            Not supported in ClickHouse Cloud
        </div>;
};

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.

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

Enable WebAssembly support in your ClickHouse configuration:

```xml theme={null}
<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

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

```bash theme={null}
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:

```sql theme={null}
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:

```sql theme={null}
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).

```text theme={null}
[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

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

```sql theme={null}
INSERT INTO system.webassembly_modules (name, code)
SELECT 'my_module', base64Decode('AGFzbQEAAAA...');
```

Optionally, provide integrity hash:

```sql theme={null}
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

```sql theme={null}
SELECT name, lower(hex(reinterpretAsFixedString(hash))) AS sha256 FROM system.webassembly_modules

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

### Delete a module

Deletion performed by `DELETE FROM system.webassembly_modules WHERE name = '...'` statement.
The predicate must be either `name = 'literal'` for exact match or `name LIKE 'pattern'` to delete every module whose name matches the pattern; no other shapes are accepted.

```sql theme={null}
DELETE FROM system.webassembly_modules WHERE name = 'collatz';

-- Bulk-delete every module whose name starts with `tmp_` (literal underscore is escaped as `\_`):
DELETE FROM system.webassembly_modules WHERE name LIKE 'tmp\_%';
```

If any existing UDFs reference one of the matched modules, the deletion fails, so you must drop those UDFs first.

## Create a WebAssembly UDF

**Syntax**:

```sql theme={null}
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]
[DETERMINISTIC]
[SHA256_HASH 'hex']
[SETTINGS key = value[, ...]];
```

**Parameters**:

* `function_name`: Name of the function in ClickHouse. May be different from the exported function name in the module.
* `FROM 'module_name' :: 'source_function_name'`: Name of the loaded WASM module and function name in WASM module to use (defaults to function\_name)
* `ARGUMENTS`: List of argument names and types (names optional and used for serialization formats that support named fields)
* `ABI`: Application Binary Interface version
  * `ROW_DIRECT`: Direct type mapping, row-by-row processing
  * `BUFFERED_V1`: Block-based processing with serialization
* `DETERMINISTIC`: Declares the function as deterministic — always returns the same output for the same input. When specified, ClickHouse may constant-fold calls where all arguments are constants: the function is evaluated once at query analysis time and the result is reused for every row.
* `SHA256_HASH`: Expected module hash for verification (auto-filled if omitted), can be used to ensure the correct WASM module loaded across different replicas.
* `SETTINGS`: Per-function settings
  * `serialization_format` String — Serialization format for ABI requires it. Default: `MsgPack`.

## ABIs Versions

To interact with ClickHouse, WebAssembly modules must adhere to one of the supported ABIs (Application Binary Interfaces).

* `ROW_DIRECT`: Direct type mapping (primitive types `Int32`, `UInt32`, `Int64`, `UInt64`, `Float32`, `Float64` only)
* `BUFFERED_V1`: Complex types with serialization

### ABI ROW\_DIRECT

Calls an exported WASM function directly per row.

* Arguments and return types as numeric types `Int32/UInt32/Int64/UInt64/Float32/Float64/Int128/UInt128`.
* Strings are not supported in this ABI.
* Signatures must match the WASM export (`i32/i64/f32/f64/v128`).
* No support functions required to be exported by the module.

For example function with signature:

```
(func (param i32 i64 f32) (result f64) ...)
```

Can be created as:

```sql theme={null}
CREATE FUNCTION my_func ARGUMENTS (Int32, UInt64, Float32) RETURNS Float64 ...
```

WebAssembly does not distinguish between signed and unsigned arguments, but rather uses different instructions to interpret the values. Thus, size of the argument should match exactly, while signedness is determined by the operations inside the function.

### ABI BUFFERED\_V1

<Note>
  This ABI is experimental and subject to change in future releases.
</Note>

Processes entire blocks at once using a (de)serialization through WASM memory. Supports any argument and return types.

Serialized data is copied to wasm memory passed as pointer to buffer (which consists of pointer to data and size of the data) to the UDF function along with the number of rows in the input. Thus, user-defined function on wasm time always accepts two `i32` arguments and returns single `i32` value.
Guest code processes the data and returns a pointer to the result buffer with serialized result data.

The guest code must provide two functions to create and destroy these buffers.

```
(module
  ;; Allocate a new buffer of specified size
  ;; Returns: handle to Buffer structure (not direct data pointer!) with pointer to data and size
  (func (export "clickhouse_create_buffer")
    (param $size i32)    ;; Size of data to allocate
    (result i32))        ;; Returns buffer handle with enough space

  ;; Free a buffer by its handle
  (func (export "clickhouse_destroy_buffer")
    (param $handle i32)  ;; Buffer handle to free
    (result))            ;; No return value

    ;; User-defined function
    (func (export "user_defined_function1")
      (param $input_buffer_handle i32)  ;; Input buffer handle
      (param $n i32)                    ;; Number of rows in input
      (result i32))                     ;; Returns output buffer handle
)
```

Example C definitions:

```c theme={null}
typedef struct {
    uint8_t * data;
    uint32_t size;
} ClickhouseBuffer;

ClickhouseBuffer * clickhouse_create_buffer(uint32_t size) { /* ... */ }

void clickhouse_destroy_buffer(ClickhouseBuffer * data) { /* ... */ }

/// Example user-defined functions
ClickhouseBuffer * user_defined_function1(ClickhouseBuffer * span, uint32_t n) { /* ... */ }
ClickhouseBuffer * user_defined_function2(ClickhouseBuffer * span, uint32_t n) { /* ... */ }
```

### Note for developing UDFs in Rust

For Rust programs we provide a helper crate [clickhouse-wasm-udf](https://crates.io/crates/clickhouse-wasm-udf) to simplify development of WebAssembly UDFs for ClickHouse. The crate provides function for memory management, so you don't need to implement `clickhouse_create_buffer` and `clickhouse_destroy_buffer` functions manually, but rather add the crate as a dependency. Also there are macros `#[clickhouse_wasm_udf]` to wrap your regular Rust functions into the required ABI format.

With the crate you can write UDFs like this:

```rust theme={null}

use clickhouse_wasm_udf_bindgen::clickhouse_udf;

#[clickhouse_udf]
pub fn some_udf(data: String) -> HashMap<String, String> {
    // Your implementation here
}

```

Macros will generate wrapper function accepting and returning buffer structures and handle serialization/deserialization automatically using `serde`.

## Host API available to modules

The following host functions may be imported and used by modules:

* `clickhouse_server_version() -> i64` — returns ClickHouse server version as integer (e.g. 25011001 for v25.11.1.1).
* `clickhouse_throw(ptr: i32, size: i32)` — throws an error with the provided message. Accepts pointer to the memory location containing the error message string and size of the string.
* `clickhouse_log(ptr: i32, size: i32)` — logs a message to ClickHouse server text log.
* `clickhouse_random(ptr: i32, size: i32)` — fills memory with random bytes.

## Settings

The following query-level settings control WebAssembly UDF execution:

* `webassembly_udf_max_fuel` — Fuel limit per WebAssembly UDF instance execution. Each WebAssembly instruction consumes some amount of fuel. Set to 0 for no limit.

* `webassembly_udf_max_memory` — Memory limit in bytes per WebAssembly UDF instance.

* `webassembly_udf_max_input_block_size` — Maximum number of rows passed to a WebAssembly UDF in a single block. Set to 0 to process all rows at once.

* `webassembly_udf_max_instances` — Maximum number of WebAssembly UDF instances that can run in parallel per function.

Example usage:

```sql theme={null}
SET webassembly_udf_max_fuel = 200000;
SELECT my_wasm_udf(column) FROM table;
```

## See also

* [ClickHouse UDF overview](/reference/functions/regular-functions/udf)
