---
title: "Native Functions (FFI)"
canonical_url: https://developer.repebble.com/guides/alloy/ffi/
last_updated: 2026-06-24
sdk_version: 4.43
---
# Native Functions (FFI)

Source: https://developer.repebble.com/guides/alloy/ffi/

The Foreign Function Interface (FFI) lets your Alloy app call native C functions directly from JavaScript. This is useful for performance-critical code, for reusing existing C libraries, or for reaching low-level functionality that isn't exposed through a JavaScript API.

> **Platform Support** : Like the rest of Alloy, FFI is available on Emery (Pebble Time 2) and Gabbro (Pebble Round 2).

An FFI binding has three parts:

1. The **native C source** that implements the functions.
2. An **`ffi` block** in `manifest.json` that lists the C sources and declares each function's signature.
3. The **`Natives` global** in your JavaScript, through which the functions are called.

## 1. Write the native C functions

Add one or more C files alongside your `mdbl.c` (for example `src/c/add.c`). The C function names must match the names you declare in the manifest:

```
// add.c#include \<stdint.h\>int32\_t add(int32\_t a, int32\_t b) {return a + b;}int32\_t addSquares(int32\_t a, int32\_t b) {return (a \* a) + (b \* b);}
```

Functions can take and return buffers and strings as well as numbers:

```
// hello.c#include \<stdint.h\>#include \<string.h\>// Fill the caller-provided buffer with bytes derived from `greeting`.void hello(char \*greeting, uint8\_t \*bytes, uint32\_t length) {size\_t len = strlen(greeting);for (uint32\_t i = 0; i \< length; i++) {bytes[i] = (uint8\_t)greeting[i % len];}}
```

## 2. Declare the functions in the manifest

In `src/embeddedjs/manifest.json`, add an `ffi` block listing your C `sources` and the `functions` with their argument and return types:

```
{"include": ["$(MODDABLE)/examples/manifest\_mod.json","$(MODDABLE)/examples/manifest\_typings.json"],"modules": {"\*": "./main"},"ffi": {"sources": ["./add.c","./hello.c"],"functions": {"add": {"arguments": ["int32\_t", "int32\_t"],"returns": "int32\_t"},"addSquares": {"arguments": ["int32\_t", "int32\_t"],"returns": "int32\_t"},"hello": {"arguments": ["char \*", "uint8\_t\*", "uint32\_t"],"returns": "void"}}}}
```

### Supported types

| C type | JavaScript value |
| --- | --- |
| `int32_t`, `uint8_t`, `uint32_t` | `Number` |
| `char*` (argument) | `String` |
| `char*`, `const char*` (return) | `String` |
| `uint8_t*`, `void*` | `ArrayBuffer` (pass `.buffer` from a typed array or `DataView`) |
| `void` | `undefined` |

Numeric arguments are passed by value. Buffers are passed by reference, so a C function can read from and write into an `ArrayBuffer` you pass in.

## 3. Make the machine FFI-aware

The C entry point (`src/c/mdbl.c`) must pass the generated `fxBuildFFI` symbol when it creates the Moddable machine:

```
#include \<pebble.h\>int main(void) {Window \*w = window\_create();window\_stack\_push(w, true);moddable\_createMachine(&(ModdableCreationRecord){.recordSize = sizeof(ModdableCreationRecord),#ifdef PBL\_DEBUG.flags = kModdableCreationFlagDebug,#endif.fxBuildFFI = fxBuildFFI,});window\_destroy(w);return 0;}
```

## 4. Call the functions from JavaScript

All declared functions are available on the global `Natives` object:

```
console.log("Hello, FFI.");trace(`Natives.add(2, 3) = ${ Natives.add(2, 3) }\n`);trace(`Natives.addSquares(3, 4) = ${ Natives.addSquares(3, 4) }\n`);const bytes = new Uint8Array(5);Natives.hello("hello", bytes.buffer, bytes.length);trace(`bytes = ${ bytes }\n`);
```

Wrap calls in a `try`/`catch` to handle errors thrown across the boundary:

```
try {const result = Natives.add(2, 3);} catch (error) {console.log("FFI Error: " + error);}
```

## Further reading

The FFI mechanism comes from the Moddable SDK. See the [XS FFI documentation](https://www.moddable.com/documentation/xs/XS%20FFI) for the full set of supported types and behaviors, and the [`helloffi` example](https://github.com/Moddable-OpenSource/pebble-examples/tree/main/helloffi) for a complete project.
