Skip to content

Repository files navigation

ttrpc-rust

Lightweight RPC for Rust, built for memory-constrained systems.

Crates.io Documentation BVT License

API documentation · Examples · ttrpc protocol · Report an issue

ttrpc-rust is a non-core subproject of containerd.

It is the Rust implementation of ttrpc: a simple RPC protocol designed for environments where memory usage and binary size matter. It uses Protocol Buffers service definitions while replacing the HTTP/2 stack with lightweight framing—making it a natural fit for container runtimes, sandboxed workloads, sidecars, and embedded system services.

Important

ttrpc reuses .proto service definitions, but it does not use the gRPC wire protocol. A ttrpc client must communicate with a ttrpc server.

Features

Capability Support
Client and server APIs Synchronous and Tokio-based asynchronous implementations
RPC styles Unary; client, server, and bidirectional streaming in async mode
Code generation Pure-Rust rust-protobuf generation, a protoc plugin, or Prost generation using protoc
Request context Timeouts, metadata, and typed RPC status codes
Transports Unix sockets, TCP, Linux/Android vsock, and Windows named pipes
Server lifecycle Service registration, listener control, and graceful shutdown
Platforms Linux, macOS, Windows, and Android

The synchronous API and rustprotobuf backend are enabled by default. Enable the async Cargo feature for the Tokio implementation and streaming RPCs. See Using Prost for the alternative protobuf backend.

Quick start

Run the examples

Clone the repository and start a synchronous server:

cargo run -p ttrpc-example --example server

In another terminal, run the client:

cargo run -p ttrpc-example --example client

Async and streaming examples are available with the same workflow:

# Unary async RPC
cargo run -p ttrpc-example --example async-server
cargo run -p ttrpc-example --example async-client

# Unary + client/server/bidirectional streaming
cargo run -p ttrpc-example --example async-stream-server
cargo run -p ttrpc-example --example async-stream-client

On Unix, append -- --tcp to any example command to use TCP instead of a Unix socket.

Add ttrpc to your project

Add the runtime, Protocol Buffers support, and build-time generator:

[dependencies]
protobuf = "3.7"
ttrpc = "0.9"

[build-dependencies]
ttrpc-codegen = "0.6"

For async clients, servers, and streaming, use the following dependency set:

[dependencies]
async-trait = "0.1"
protobuf = "3.7"
ttrpc = { version = "0.9", features = ["async"] }
tokio = { version = "1", features = ["macros", "rt"] }

[build-dependencies]
ttrpc-codegen = "0.6"

Define a service in proto/greeter.proto:

syntax = "proto3";

package example;

message HelloRequest  { string name = 1; }
message HelloResponse { string message = 1; }

service Greeter {
  rpc SayHello(HelloRequest) returns (HelloResponse);
}

Generate the message types, client, and server trait from build.rs—no protoc installation is required:

use ttrpc_codegen::{Codegen, Customize, ProtobufCustomize};

fn main() {
    println!("cargo:rerun-if-changed=proto/greeter.proto");

    Codegen::new()
        .out_dir(std::env::var("OUT_DIR").unwrap())
        .input("proto/greeter.proto")
        .include("proto")
        .rust_protobuf()
        .customize(Customize {
            gen_mod: true,
            ..Default::default()
        })
        .rust_protobuf_customize(ProtobufCustomize::default().gen_mod_rs(true))
        .run()
        .expect("failed to generate ttrpc bindings");
}

Canonical Google well-known type imports, such as google/protobuf/timestamp.proto, are available automatically and do not require an additional include path.

Include the generated modules in your crate:

mod rpc {
    include!(concat!(env!("OUT_DIR"), "/mod.rs"));
}

The generator creates:

  • greeter.rs — Protocol Buffers messages
  • greeter_ttrpc.rs — the Greeter service trait, GreeterClient, and service registration helper
  • mod.rs — generated module declarations

Implement the generated service trait, register it with ttrpc::Server, and connect with ttrpc::Client:

// Server
let service = rpc::greeter_ttrpc::create_greeter(Arc::new(GreeterService));
let mut server = ttrpc::Server::new()
    .bind("unix:///tmp/greeter.sock")?
    .register_service(service);
server.start()?;

// Client
let channel = ttrpc::Client::connect("unix:///tmp/greeter.sock")?;
let client = rpc::greeter_ttrpc::GreeterClient::new(channel);
let response = client.say_hello(Default::default(), &request)?;

See the complete synchronous and asynchronous servers, plus the streaming example, for production-shaped implementations.

Generate async bindings

Set async_all during code generation:

.customize(Customize {
    async_all: true,
    gen_mod: true,
    ..Default::default()
})

You can generate only one side with async_client or async_server. Streaming services require async bindings.

Using Prost

Prost support in this checkout uses prost 0.13 and requires protoc on PATH for both the runtime build and application code generation. Use a local dependency on the checkout to try the current implementation:

[dependencies]
prost = "0.13"
ttrpc = { path = "../ttrpc-rust", default-features = false, features = ["sync", "prost"] }

[build-dependencies]
ttrpc-codegen-prost = { version = "0.1", path = "../ttrpc-rust/ttrpc-codegen-prost" }

Adjust the paths to your checkout. The ttrpc-codegen-prost package is separate from the rust-protobuf ttrpc-codegen package; its first release is planned as version 0.1. The two protobuf backend features are mutually exclusive. Because disabling default features also disables sync, list the runtime features explicitly.

Use .prost() in build.rs. Set Customize::async_all = true for async bindings and enable the runtime's async feature; generated async bindings also require async-trait in your application. Streaming requires async bindings. The Prost generator guide includes a complete dependency setup, service definition, build script, and generated-module import.

Generated Rust files and modules follow the protobuf package rather than the input filename. For example, package example; produces example.rs, containing both message types and service bindings. Rust identifier casing may also differ from rust-protobuf, such as Cpu instead of CPU; use the generated APIs for your selected backend. The protobuf schema and ttrpc wire protocol remain the same.

The Prost examples demonstrate synchronous, asynchronous, and streaming calls over Unix sockets. Run a server and client in separate terminals:

cargo run --manifest-path example-prost/Cargo.toml --example server
cargo run --manifest-path example-prost/Cargo.toml --example client

On Unix, security_extension is available with either backend. Generate local API documentation for Prost, both runtimes, and the security extension with:

RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --no-default-features \
  --features sync,async,prost,security_extension --open

The docs.rs configuration selects rustprotobuf. The local command above lets you inspect the Prost APIs and fails on documentation warnings. The generator's own documentation is built separately:

RUSTDOCFLAGS="-D warnings" cargo doc --manifest-path ttrpc-codegen-prost/Cargo.toml --no-deps --open

Transport addresses

Address Transport Platforms
unix:///run/service.sock Unix domain socket Unix
unix://@service Abstract Unix domain socket Linux, Android
tcp://127.0.0.1:5000 TCP Unix
vsock://3:1024 VM socket Linux, Android
\\.\pipe\service Windows named pipe Windows

ttrpc does not provide TLS. If you expose TCP beyond a trusted boundary, secure the transport at the deployment or network layer.

Workspace

Crate Purpose
ttrpc Sync and async client/server runtime
ttrpc-codegen Build-script API for parsing .proto files and generating Rust code
ttrpc-compiler Service code generator and protoc plugin
example End-to-end unary and streaming examples using rust-protobuf
ttrpc-codegen-prost Standalone build-script generator using Prost and protoc
example-prost Standalone unary and streaming examples using Prost

Compatibility

  • Runtime and code generators minimum supported Rust version: 1.80
  • With Rust 1.80–1.84, a fresh dependency resolution may select transitive crates requiring a newer toolchain. If needed, constrain tempfile to <3.25 in your application's Cargo.toml. For indexmap, use <2.12 on Rust 1.80–1.81 or <2.14 on Rust 1.82–1.84.
  • Repository development toolchain: see rust-toolchain.toml
  • Default features: sync, rustprotobuf
  • Optional features: async, prost, security_extension (Unix only)
  • Enable exactly one of rustprotobuf and prost; never use --all-features for the runtime.
  • Keep protobuf, protobuf-codegen, and generated sources on matching versions. Regenerate bindings after changing the Protocol Buffers runtime version.

Development

# The "prost" and "rustprotobuf" features are mutually exclusive, so never
# build the root crate with --all-features; `make test` covers both backends.
make test

# Run formatting, Clippy, and strict API documentation checks
make check-all

# The Prost generator is a separate workspace
make -C ttrpc-codegen-prost test
make -C ttrpc-codegen-prost check

Project details

ttrpc-rust is a non-core containerd subproject, licensed under the Apache License 2.0.

As a containerd subproject, you will find the:

information in the containerd/.project repository.

About

Rust implementation of ttrpc (GRPC for low-memory environments)

Resources

Security policy

Stars

370 stars

Watchers

21 watching

Forks

Releases

Packages

Used by

Contributors

Languages