---
title: "FFI Bindings: Go and C/C++"
description: "Use the Nym SDK from Go and C/C++ via FFI bindings. Covers mixnet messaging, anonymous replies, and TcpProxy lifecycle from non-Rust languages."
schemaType: "TechArticle"
section: "Developers"
lastUpdated: "2026-03-15"
---

# FFI Bindings

import { Callout } from 'nextra/components'

The SDK exposes FFI bindings for Go and C/C++. The source lives in [`sdk/ffi`](https://github.com/nymtech/nym/tree/develop/sdk/ffi):

```
ffi
├── cpp      # C/C++ bindings (manual C FFI)
├── go       # Go bindings (via uniffi-bindgen-go)
└── shared   # Shared Rust implementation
```

Core logic lives in `shared/` and is imported into language-specific wrappers. The shared layer handles thread safety and runs client operations on blocking threads on the Rust side of the FFI boundary.

## What's exposed

**Mixnet** (Go and C/C++): ephemeral and persistent client creation, sending messages, anonymous replies via SURBs, listening for incoming messages.

**TcpProxy** (Go only): client and server creation and lifecycle.

<Callout type="warning">
The TcpProxy module is deprecated. For new projects, use the [Stream module](./stream) instead.
</Callout>

**Client Pool and Stream** have no standalone FFI bindings yet. The TcpProxy bindings use the Client Pool internally.

## Quick example (Go)

```go
// Initialise an ephemeral client
bindings.InitEphemeral()

// Get our Nym address
addr, _ := bindings.GetSelfAddress()

// Send a message through the Mixnet
bindings.SendMessage(addr, "hello from Go")

// Listen for incoming messages
msg, _ := bindings.ListenForIncoming()
fmt.Println("Received:", msg.Message)

// Reply anonymously via SURBs
bindings.Reply(msg.Sender, "reply from Go")
```

## Quick example (C++)

The C++ bindings use callbacks for return values and a `ReceivedMessage` struct for incoming data:

```cpp
extern "C" {
    struct ReceivedMessage {
        const uint8_t* message;
        size_t size;
        const char* sender_tag;
    };

    void init_logging();
    char init_ephemeral();
    char get_self_address(void (*callback)(const char*));
    char send_message(const char*, const char*);
    char listen_for_incoming(void (*callback)(ReceivedMessage));
    char reply(const char*, const char*);
}

// Get address via callback
char addr[134];
void on_address(const char* s) { strcpy(addr, s); }

// Receive message via callback
char sender_tag[22];
void on_message(ReceivedMessage msg) {
    std::cout << "Received: " << msg.message << std::endl;
    strcpy(sender_tag, msg.sender_tag);
}

int main() {
    init_ephemeral();
    get_self_address(on_address);
    send_message(addr, "hello from C++");
    listen_for_incoming(on_message);
    reply(sender_tag, "reply from C++");
}
```

## Building

Each language has a `build.sh` script that compiles the Rust shared library and generates bindings. See the README in each directory for prerequisites.

## Examples and source

- [Go mixnet example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/go/example.go): init, send, receive, SURB reply
- [Go TcpProxy example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/go/proxy_example.go): proxy client and server with TCP echo
- [C++ example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/cpp/src/main.cpp): same flow using Boost threads
- [`sdk/ffi` source](https://github.com/nymtech/nym/tree/develop/sdk/ffi): full source and build scripts
