gRPC in Rust no longer needs a C++ compiler to build, or a C crypto library to secure.
Today we’re releasing OxiRPC 0.2.0 — the COOLJAPAN Pure-Rust gRPC stack: a production-ready facade over tonic 0.14 that wires its proto codegen, TLS, and message compression entirely out of the oxi* ecosystem.
No protoc. No OpenSSL. No ring by default. No FFI, no -sys crates, no apt-get install protobuf-compiler. The default feature closure of OxiRPC is 100% Pure Rust and FFI-free — and so is the entire --all-features closure of the facade.
Why OxiRPC
gRPC is the lingua franca of service-to-service communication, but standing up a gRPC service in Rust has always dragged in a native toolchain. You need the protoc C++ compiler at build time to turn .proto files into code. You need a TLS backend — almost always OpenSSL or ring — to secure the wire. And the moment you turn on message compression, you pull in flate2 or the zstd C crate. Three separate FFI dependencies, three separate ways for a clean cargo build to fail inside a slim container.
OxiRPC removes all three. It keeps tonic’s familiar gRPC-over-HTTP/2 transport and its ergonomic builder API, then replaces every native edge underneath:
| Old dependency | Replaced by |
|---|---|
protoc binary | OxiProto (oxiproto-build + protox) |
openssl-sys | OxiTLS (rustls + rustls-rustcrypto) |
ring | OxiTLS pure_provider() |
flate2 | OxiARC oxiarc-deflate |
zstd C crate | OxiARC oxiarc-zstd |
Run cargo tree -p oxirpc --edges normal on default features or --all-features and you will find zero occurrences of protoc, openssl, openssl-sys, ring, aws-lc-sys, native-tls, flate2, or the zstd C crate. That is the whole point: a fresh container builds, and the binary speaks gRPC, with nothing native in the way.
What we built
OxiRPC is a nine-crate workspace, exported through a single oxirpc facade so you can depend on one crate and reach everything.
1. The facade and core (oxirpc, oxirpc-core)
oxirpc re-exports the whole stack under one dependency. oxirpc-core holds the foundation: error and status types, metadata, timeouts, the encoding layer, the wire layer, and TLS plumbing.
2. Build-time codegen with no protoc (oxirpc-build)
Drop oxirpc-build into [build-dependencies] and call compile_protos from your build.rs. It compiles .proto files via oxiproto-build + protox — pure Rust, no protoc binary to install or pin. Each proto set’s descriptor is cached under $OUT_DIR/.oxirpc-cache/fds-<hash>.bin, keyed by a stable hash of the sorted input paths, so independent compile_to_fds calls sharing one $OUT_DIR never collide.
3. The wire layer (oxirpc-core::wire)
A native HTTP/2 gRPC wire implementation: FrameEncoder/FrameDecoder as tokio-util codecs, GrpcRequestHeaders/GrpcResponseHeaders, gRPC status-trailer encoding with percent-encoding, a compression-aware MessagePipeline, and a Deadline + timeout codec. The bidirectional driver (drive_bidi / drive_bidi_with_encoding) is truly streaming — built on an incremental FrameDecoder, it can deliver response N before request N+1.
4. Pure-Rust TLS (oxirpc-core::tls, oxirpc-client::tls_connector)
PureRustTlsConnector wires rustls together with OxiTLS’s pure_provider() into tonic-transport’s connect_with_connector. The result is end-to-end Pure-Rust TLS on both client and server — no ring, no OpenSSL — without forking tonic.
5. Pure-Rust compression (oxirpc-core::encoding)
CompressionEncoding (Identity / Gzip / Zstd) is backed by oxiarc-deflate and oxiarc-zstd, with wire-level FLAG_COMPRESSED framing in the gRPC-Web codec. No flate2, no zstd C crate on any feature edge.
6. Client and server (oxirpc-client, oxirpc-server)
The client provides a ClientBuilder, a channel pool, load balancing (round-robin, weighted, pick-first), resilience, and xDS/ADS support. The server provides a ServerBuilder with routing, a native service registry, compression layers, and TLS. A native HTTP/2 server (NativeServiceRegistry) adds streaming bidi handling.
7. The protocol extras (oxirpc-reflect, oxirpc-health, oxirpc-web)
oxirpc-reflect implements gRPC server reflection v1 + v1alpha (with an optional oxiproto-reflect DescriptorPool backend). oxirpc-health implements the gRPC health-checking protocol v1, with per-service status mirroring, bulk set_all_serving / set_all_not_serving, and Watch streaming. oxirpc-web provides a gRPC-Web bridge — a GrpcWebLayer that wraps any tonic Router, handling binary and base64 text mode, compression-aware data frames, trailer-frame synthesis, and a CorsPolicy with wildcard, per-origin, and allow_credentials modes.
Getting Started
Add OxiRPC as a runtime dependency and the build helper as a build dependency:
# Cargo.toml
[dependencies]
oxirpc = { version = "0.2", features = ["client", "server", "tls", "health"] }
[build-dependencies]
oxirpc-build = "0.2"
Compile your protos at build time — no protoc required:
// build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
oxirpc_build::compile_protos(&["proto/greeter.proto"], &["proto/"])?;
Ok(())
}
Stand up a server with the familiar builder API:
// Server
use oxirpc::{ServerBuilder, OxiRpcError};
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> Result<(), OxiRpcError> {
let addr: SocketAddr = "[::1]:50051".parse().expect("valid addr");
ServerBuilder::new()
.add_service(my_service())
.serve(addr)
.await
}
And connect a client:
// Client
use oxirpc::ClientBuilder;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let channel = ClientBuilder::new("http://[::1]:50051")
.connect()
.await?;
// let client = MyServiceClient::new(channel);
Ok(())
}
To turn everything on at once:
cargo add oxirpc --features "client,server,tls,health,reflect,web,gzip,zstd"
Highlights
- gRPC over HTTP/2, tonic-style —
ServerBuilder/ClientBuilder, channel pool, load balancing, and resilience. - No-protoc codegen —
.protofiles compile inbuild.rsvia OxiProto +protox, with collision-free per-input descriptor caching. - End-to-end Pure-Rust TLS —
PureRustTlsConnectoroverrustls+ OxiTLS, on both client and server. - Truly-streaming bidi — an incremental
FrameDecoderdriver that interleaves requests and responses rather than buffering. - Pure-Rust compression — gzip and zstd gRPC message compression backed by OxiARC, no C compression crates.
- Server reflection v1 + v1alpha and the health-checking protocol v1 with Watch streaming.
- gRPC-Web bridge — a
GrpcWebLayerover any tonicRouter, with binary/base64 modes and a configurableCorsPolicy. - A full interceptor library —
BearerAuth,Tracing,Deadline, rate limiting, metrics, logging, retry, and circuit breaker, composable viaInterceptorChain, plus anAsyncInterceptorwired on both client and server.
Tips
- Default features are empty.
oxirpc’s default feature set is[]— zero deps beyond tonic + prost + tokio. Opt in to exactly what you serve:client,server,tls,health,reflect,web,gzip,zstd, orfullfor the complete Pure-Rust closure. - Need aws-lc-rs crypto? As of 0.2.0 the
aws-lcfeature has been removed from the facade so thatoxirpc --all-featuresstays 100% Pure Rust. If you specifically want aws-lc-rs-backed TLS, depend onoxirpc-adapter-aws-lcdirectly and enable itsaws-lcfeature. - Async interceptors run at the right edge. On the client,
NativeChannelBuilder::with_async_interceptorruns before every H2 stream opens — inject metadata or abort with aStatus. On the server,NativeServiceRegistry::with_async_interceptorruns before the matched handler — mutate headers or return a gRPC error. A blanket impl lets a closure returning a future be anAsyncInterceptor, so no manual struct is needed. - Reflection can share OxiProto’s descriptor pool. Enable the
oxiprotofeature to backNativeReflectionServicewith anoxiproto-reflectDescriptorPool, integrating reflection with OxiProto’s type system. - Verify the FFI floor yourself.
cargo tree -p oxirpc --edges normalon default features or--all-featuresshould show noprotoc,openssl,ring,aws-lc-sys,native-tls,flate2, orzstdC crate. Runcargo nextest runfor the default suite, orcargo fuzz run wire_frameto fuzz the frame decoder.
Part of the COOLJAPAN ecosystem
OxiRPC is one piece of NoFFI — the COOLJAPAN initiative to replace every C/C++/Fortran/-sys FFI dependency in the Rust ecosystem with a clean, memory-safe, 100% Pure Rust implementation. OxiRPC sits at the networking layer and stitches three siblings together: it depends on OxiProto for descriptor parsing (replacing protoc), OxiTLS for its crypto provider and certificate types (replacing OpenSSL and ring), and OxiARC for compression (replacing flate2 and zstd-sys).
It is, in turn, the gRPC backbone for the rest of the stack — powering oxirouter (gateway ingress and service-to-service), oxigenai (LLM inference server API), oxigdal-cluster (geospatial distributed coordination), oxionnx (model serving), and oxirs (SPARQL-over-gRPC).
Repository: https://github.com/cool-japan/oxirpc
Star the repo if you want gRPC in Rust that builds in a bare container and ships as a single static binary.
Pure Rust gRPC — sovereign, safe, and FFI-free.
— KitaSan at COOLJAPAN OÜ June 23, 2026