Lightweight RPC for Rust, built for memory-constrained systems.
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.
| 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.
Clone the repository and start a synchronous server:
cargo run -p ttrpc-example --example serverIn another terminal, run the client:
cargo run -p ttrpc-example --example clientAsync 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-clientOn Unix, append -- --tcp to any example command to use TCP instead of a Unix socket.
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 messagesgreeter_ttrpc.rs— theGreeterservice trait,GreeterClient, and service registration helpermod.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.
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.
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 clientOn 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 --openThe 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| 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.
| 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 |
- 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
tempfileto<3.25in your application'sCargo.toml. Forindexmap, use<2.12on Rust 1.80–1.81 or<2.14on 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
rustprotobufandprost; never use--all-featuresfor the runtime. - Keep
protobuf,protobuf-codegen, and generated sources on matching versions. Regenerate bindings after changing the Protocol Buffers runtime version.
# 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 checkttrpc-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.