MCPcopy Index your code
hub / github.com/connectrpc/connect-rust

github.com/connectrpc/connect-rust @v0.8.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.8.1 ↗ · + Follow
3,748 symbols 9,114 edges 190 files 870 documented · 23%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

connectrpc

crates.io docs.rs CI MSRV deps.rs License

A Tower-based Rust implementation of ConnectRPC, serving Connect, gRPC, and gRPC-Web clients over HTTP with binary or JSON protobuf messages.

Status: pre-1.0. The API surface is settling but may shift in 0.x. Production-quality runtime: passes the full ConnectRPC conformance suite — 3,600 server and 6,872 client tests across the three protocols.

MSRV: Rust 1.88 (declared on the workspace, verified in CI).

Documentation:

  • User guide - long-form coverage of installation, code generation, server/client usage, streaming, tower middleware, TLS, and errors.
  • examples/ - runnable end-to-end examples (streaming, tower middleware, TLS, multi-service, browser/wasm, Bazel).
  • docs.rs - API reference.

Overview

connectrpc provides:

  • connectrpc — A Tower-based runtime library implementing the Connect protocol
  • protoc-gen-connect-rust — A protoc plugin that generates service traits, clients, and message types
  • connectrpc-buildbuild.rs integration for generating code at build time
  • connectrpc-health — The standard grpc.health.v1.Health service, for grpc_health_probe / kubelet gRPC probes / service-mesh health checks
  • connectrpc-reflection — The standard gRPC server reflection service (grpc.reflection.v1 + v1alpha), so grpcurl, buf curl, Postman, and grpcui can discover and call your services

The runtime is built on tower::Service, making it framework-agnostic. It integrates with any tower-compatible HTTP framework including Axum, Hyper, and others.

Quick Start

Define your service

// greet.proto
syntax = "proto3";
package greet.v1;

service GreetService {
  rpc Greet(GreetRequest) returns (GreetResponse);
}

message GreetRequest {
  string name = 1;
}

message GreetResponse {
  string greeting = 1;
}

Generate Rust code

Two workflows are supported. Both produce the same runtime API; pick the one that fits your build pipeline.

Option A - buf generate (recommended for checked-in code)

Runs two codegen plugins (protoc-gen-buffa for message types, protoc-gen-connect-rust for service stubs) and protoc-gen-buffa-packaging twice to assemble the mod.rs module tree for each output directory. The codegen plugins are invoked per-file; only the packaging plugin needs strategy: all.

Installing the plugins

protoc-gen-buffa and protoc-gen-buffa-packaging ship from the buffa repo - see its release page for binaries or cargo install.

For protoc-gen-connect-rust, three options:

1. Download a pre-built binary from the GitHub release. Releases ship Linux (x86_64, aarch64), macOS (x86_64, aarch64), and Windows (x86_64) binaries, each with a SHA-256 checksum, a Sigstore signature (.sig + .pem), and a GitHub-native build provenance attestation.

VERSION=v0.8.0
PLATFORM=linux-x86_64        # or darwin-aarch64, etc.
BASE=https://github.com/connectrpc/connect-rust/releases/download/${VERSION}
BIN=protoc-gen-connect-rust-${VERSION}-${PLATFORM}

curl -fSL -o "${BIN}"        "${BASE}/${BIN}"
curl -fSL -o "${BIN}.sig"    "${BASE}/${BIN}.sig"
curl -fSL -o "${BIN}.pem"    "${BASE}/${BIN}.pem"
curl -fSL -o checksums-sha256.txt "${BASE}/checksums-sha256.txt"

# Verify the checksum.
grep " ${BIN}\$" checksums-sha256.txt | sha256sum -c -

# Verify the GitHub-native attestation (no .sig/.pem download needed).
gh attestation verify "${BIN}" --repo connectrpc/connect-rust

# Or verify the cosign signature directly.
cosign verify-blob \
  --certificate "${BIN}.pem" \
  --signature "${BIN}.sig" \
  --certificate-identity "https://github.com/connectrpc/connect-rust/.github/workflows/release.yml@refs/tags/${VERSION}" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  "${BIN}"

install -m 0755 "${BIN}" /usr/local/bin/protoc-gen-connect-rust

2. Build from source via cargo. Pulls the latest published connectrpc-codegen crate from crates.io and installs the binary into $CARGO_HOME/bin:

cargo install --locked connectrpc-codegen

3. Buf Schema Registry remote plugin (planned). Once accepted upstream the plugin will be runnable as remote: buf.build/connectrpc/connect-rust in buf.gen.yaml, with no local install step.

# buf.gen.yaml
version: v2
plugins:
  - local: protoc-gen-buffa
    out: src/generated/buffa
    opt: [views=true, json=true]
  - local: protoc-gen-buffa-packaging
    out: src/generated/buffa
    strategy: all
  - local: protoc-gen-connect-rust
    out: src/generated/connect
    opt: [buffa_module=crate::proto]
  - local: protoc-gen-buffa-packaging
    out: src/generated/connect
    strategy: all
    opt: [filter=services]
// src/lib.rs
#[path = "generated/buffa/mod.rs"]
pub mod proto;
#[path = "generated/connect/mod.rs"]
pub mod connect;

buffa_module=crate::proto tells the service-stub generator where you mounted the buffa output. For a method input type greet.v1.GreetRequest it emits crate::proto::greet::v1::GreetRequest - the crate::proto root you named, then the proto package as nested modules, then the type. The second packaging invocation uses filter=services so the connect tree's mod.rs only include!s files that actually have service stubs in them. Changing the mount point requires regenerating.

The underlying option is extern_path=.=crate::proto - same format the Buf Schema Registry uses when generating Cargo SDKs. buffa_module=X is shorthand for the . catch-all case. Any module an extern_path points at must be buffa-generated code from buffa 0.8.0 or newer with views enabled (buffa-types 0.8+ for the well-known types): the service stubs rely on the HasMessageView impls and owned-view wrappers that buffa generates alongside each message, just as they rely on the JSON serialization impls.

Option B - build.rs (generated at build time)

Unified output: message types and service stubs in one file per proto, assembled via a single include!. No plugin binaries required at build time.

[build-dependencies]
connectrpc-build = "0.8"
// build.rs
fn main() {
    connectrpc_build::Config::new()
        .files(&["proto/greet.proto"])
        .includes(&["proto/"])
        .include_file("_connectrpc.rs")
        .compile()
        .unwrap();
}
// lib.rs
pub mod proto {
    connectrpc::include_generated!();
}

Implement the server

use connectrpc::{RequestContext, Response, ServiceRequest, ServiceResult};

struct MyGreetService;

impl GreetService for MyGreetService {
    async fn greet(
        &self,
        _ctx: RequestContext,
        request: ServiceRequest<'_, GreetRequest>,
    ) -> ServiceResult<GreetResponse> {
        // `request` derefs to the view — string fields are borrowed `&str`
        // directly from the request buffer (zero-copy). The borrow lives for
        // the duration of the call; use `request.to_owned_message()` for
        // anything that must outlive it (e.g. `tokio::spawn`).
        Response::ok(GreetResponse {
            greeting: format!("Hello, {}!", request.name),
            ..Default::default()
        })
    }
}

With Axum (recommended)

use axum::{Router, routing::get};
use connectrpc::Router as ConnectRouter;
use std::sync::Arc;

let connect = ConnectRouter::new().add_service(Arc::new(MyGreetService));

// Plain HTTP liveness probe for `kubectl`'s httpGet style. For the
// standard gRPC Health protocol (grpc_health_probe, kubelet `grpc:`
// probes), mount `connectrpc_health::HealthService` on the Connect
// router instead — see docs/guide.md#health-checking.
let app = Router::new()
    .route("/health", get(|| async { "OK" }))
    .fallback_service(connect.into_axum_service());

let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await?;

Standalone server

For simple cases, enable the server feature for a built-in hyper server:

use connectrpc::{Router, Server};
use std::sync::Arc;

let router = Router::new().add_service(Arc::new(MyGreetService));

Server::new(router).serve("127.0.0.1:8080".parse()?).await?;

Client

Enable the client feature for HTTP client support with connection pooling:

use connectrpc::client::{HttpClient, ClientConfig};

let http = HttpClient::plaintext();  // cleartext http:// only; use with_tls() for https://
let config = ClientConfig::new("http://localhost:8080".parse()?);
let client = GreetServiceClient::new(http, config);

let response = client.greet(GreetRequest {
    name: "World".into(),
}).await?;

Per-call options and client-wide defaults

Generated clients expose both a no-options convenience method and a _with_options variant for per-call control (timeout, headers, max message size, compression override):

use connectrpc::client::CallOptions;
use std::time::Duration;

// Per-call timeout
let response = client.greet_with_options(
    GreetRequest { name: "World".into() },
    CallOptions::default().with_timeout(Duration::from_secs(5)),
).await?;

For options you want on every call (e.g. auth headers, a default timeout), set them on ClientConfig instead — the no-options method picks them up automatically:

let config = ClientConfig::new("http://localhost:8080".parse()?)
    .with_default_timeout(Duration::from_secs(30))
    .with_default_header("authorization", "Bearer ...");

let client = GreetServiceClient::new(http, config);

// Uses the 30s timeout and auth header without repeating them:
let response = client.greet(request).await?;

Per-call CallOptions override config defaults (options win).

Streaming, interceptors, middleware, TLS

The Quick Start above shows the unary path. For everything else, see the user guide and the focused examples:

Feature Flags

Feature Default Description
json Yes JSON codec for protobuf messages. Disable (with codegen no_json) for proto-only builds — see Proto-only builds
gzip Yes Gzip compression via flate2
zstd Yes Zstandard compression via zstd
streaming Yes Streaming compression via async-compression
client No HTTP client transports (plaintext)
client-tls No TLS for client transports (HttpClient::with_tls, Http2Connection::connect_tls)
server No Standalone hyper-based server
server-tls No TLS for the built-in server (Server::with_tls)
tls No Convenience: enables both server-tls + client-tls
axum No Axum framework integration

wasm32

The core crate compiles for wasm32-unknown-unknown. Generated clients are generic over ClientTransport, so they work on wasm with a custom transport (e.g. web-sys::fetch). The client/server/tls features require platform networking and zstd requires native C compilation. See examples/wasm-client for a complete Fetch-based transport.

[dependencies]
connectrpc = { version = "0.8", default-features = false, features = ["gzip"] }

Minimal build (no compression)

```tom

Extension points exported contracts — how you extend this code

Dispatcher (Interface)
Method-path-to-handler dispatch. [`ConnectRpcService`](crate::ConnectRpcService) is generic over this trait. The defaul [22 …
connectrpc/src/dispatcher.rs
FortuneServiceClient (Interface)
FortuneServiceClient is a client for the fortune.v1.FortuneService service. [4 implementers]
benches/rpc-go/gen/genconnect/fortune.connect.go
Checker (Interface)
Reports the health of services on this server. # Example ```no_run use connectrpc::ConnectError; use connectrpc_health [2 …
connectrpc-health/src/checker.rs
Encodable (Interface)
Encodes to the same wire bytes as proto message `M`. This is the bound on the response body in generated trait methods. [55 …
connectrpc/src/response.rs
FortuneServiceHandler (Interface)
FortuneServiceHandler is an implementation of the fortune.v1.FortuneService service. [4 implementers]
benches/rpc-go/gen/genconnect/fortune.connect.go
ServiceRegister (Interface)
Registers a generated service implementation with a [`Router`]. Implementations are emitted by `connectrpc-codegen`. Th [18 …
connectrpc/src/router.rs
BenchServiceClient (Interface)
BenchServiceClient is a client for the bench.v1.BenchService service. [3 implementers]
benches/rpc-go/gen/genconnect/bench.connect.go
ClientTransport (Interface)
Trait for types that can be used as ConnectRPC client transports. This is automatically implemented for any `tower::Ser [6 …
connectrpc/src/client/mod.rs

Core symbols most depended-on inside this repo

ok
called by 127
connectrpc/src/response.rs
clone
called by 106
connectrpc/src/request.rs
header
called by 86
connectrpc/src/response.rs
send
called by 77
connectrpc/src/client/mod.rs
with_spec
called by 74
connectrpc/src/router.rs
local_addr
called by 69
connectrpc/src/server.rs
lock
called by 65
connectrpc-health/src/static_checker.rs
unimplemented_unary
called by 62
connectrpc/src/dispatcher.rs

Shape

Method 1,795
Function 1,232
Class 582
Interface 60
Enum 57
Struct 20
TypeAlias 2

Languages

Rust95%
Go5%
Python1%

Modules by API surface

connectrpc/src/client/mod.rs263 symbols
connectrpc/src/service.rs174 symbols
connectrpc/src/server.rs144 symbols
connectrpc-codegen/src/codegen.rs119 symbols
connectrpc/src/compression.rs109 symbols
conformance/src/generated/buffa/connectrpc.conformance.v1.service.__view.rs102 symbols
benches/rpc-go/gen/bench.pb.go102 symbols
benches/rpc/src/generated/buffa/echo_bloat.__view.rs87 symbols
connectrpc/src/response.rs82 symbols
benches/rpc/src/generated/buffa/bench.__view.rs75 symbols
connectrpc/src/interceptor.rs73 symbols
connectrpc/src/client/http2.rs72 symbols

For agents

$ claude mcp add connect-rust \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact