containerd/ttrpc-rust

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

Rust

371

550 commits

updated Oct 9, 2026

See the code

README

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

CapabilitySupport
Client and server APIsSynchronous and Tokio-based asynchronous implementations
RPC stylesUnary; client, server, and bidirectional streaming in async mode
Code generationPure-Rust rust-protobuf generation, a protoc plugin, or Prost generation using protoc
Request contextTimeouts, metadata, and typed RPC status codes
TransportsUnix sockets, TCP, Linux/Android vsock, and Windows named pipes
Server lifecycleService registration, listener control, and graceful shutdown
PlatformsLinux, 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.10"

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

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

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

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

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 uses prost 0.13 and requires protoc on PATH for both the runtime build and application code generation:

[dependencies]
prost = "0.13"
ttrpc = { version = "0.10", default-features = false, features = ["sync", "prost"] }

[build-dependencies]
ttrpc-codegen-prost = "0.1"

The ttrpc-codegen-prost package is separate from the rust-protobuf ttrpc-codegen package and uses its own version line. 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

AddressTransportPlatforms
unix:///run/service.sockUnix domain socketUnix
unix://@serviceAbstract Unix domain socketLinux, Android
tcp://127.0.0.1:5000TCPUnix
vsock://3:1024VM socketLinux, Android
\\.\pipe\serviceWindows named pipeWindows

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

Workspace

CratePurpose
ttrpcSync and async client/server runtime
ttrpc-codegenBuild-script API for parsing .proto files and generating Rust code
ttrpc-compilerService code generator and protoc plugin
exampleEnd-to-end unary and streaming examples using rust-protobuf
ttrpc-codegen-prostStandalone build-script generator using Prost and protoc
example-prostStandalone 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.

For release notes and API migration details, see the runtime, compiler, and codegen changelogs.

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.

containerd/ttrpc-rust

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

Rust

371

550 commits

updated Oct 9, 2026

See the code

README

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

CapabilitySupport
Client and server APIsSynchronous and Tokio-based asynchronous implementations
RPC stylesUnary; client, server, and bidirectional streaming in async mode
Code generationPure-Rust rust-protobuf generation, a protoc plugin, or Prost generation using protoc
Request contextTimeouts, metadata, and typed RPC status codes
TransportsUnix sockets, TCP, Linux/Android vsock, and Windows named pipes
Server lifecycleService registration, listener control, and graceful shutdown
PlatformsLinux, 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.10"

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

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

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

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

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 uses prost 0.13 and requires protoc on PATH for both the runtime build and application code generation:

[dependencies]
prost = "0.13"
ttrpc = { version = "0.10", default-features = false, features = ["sync", "prost"] }

[build-dependencies]
ttrpc-codegen-prost = "0.1"

The ttrpc-codegen-prost package is separate from the rust-protobuf ttrpc-codegen package and uses its own version line. 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

AddressTransportPlatforms
unix:///run/service.sockUnix domain socketUnix
unix://@serviceAbstract Unix domain socketLinux, Android
tcp://127.0.0.1:5000TCPUnix
vsock://3:1024VM socketLinux, Android
\\.\pipe\serviceWindows named pipeWindows

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

Workspace

CratePurpose
ttrpcSync and async client/server runtime
ttrpc-codegenBuild-script API for parsing .proto files and generating Rust code
ttrpc-compilerService code generator and protoc plugin
exampleEnd-to-end unary and streaming examples using rust-protobuf
ttrpc-codegen-prostStandalone build-script generator using Prost and protoc
example-prostStandalone 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.

For release notes and API migration details, see the runtime, compiler, and codegen changelogs.

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.

Project health

Overall

6.2/10

Maintained

10/10

Code review

10/10
OpenSSF Scorecard

Significant stargazers

Stepan Koltsov

537 followers · starred Sep 2025

mark

229 followers · starred Apr 2022

Xuan Zhang

631 followers · starred Jan 2026

Jiaxiao Zhou

404 followers · starred Apr 2024