
gRPC-Rust(v0.9)を動かしてみる
Introduction
2026 年 5 月 28 日に公式 gRPC-Rust(v0.9.0)の preview がリリースされ、後日ロードマップも公開されました。
2026年6月現在、announcement には以下のように記述もあります。
gRPC Server support is coming soon
現状どうなっているのかよくわかりません。
なので、grpc/grpc-rust リポジトリを確認して動作確認してみました。
本記事の結論まとめは以下。
- 公式
grpc0.9.0 は クライアントのみ public。サーバコードはリポジトリ内に既にあるがpub(crate)で外部から使えない。 - もともと tonic 作者の Lucio Franco 氏が Tonic joins gRPC(2026-05-19) で gRPC org への統合を発表。
- 公式は新
grpcクレートを "production-ready, long-term replacement for Tonic users" と位置づけ - 現 preview 0.9.0 の実装は内部で tonic を transport として使用.当面は両者が共存
- 設計レベルでは tonic とは違う方向(HTTP/2 プリミティブ非露出 / Arena メモリモデルなど)が公式 blog で語られている(Client API Evolution pt.1 / pt.2)。
- 今すぐ client/server を動かしたいなら tonic v0.14.xを使う。公式 Quick Start も
helloworld-server(tonic)+grpc-helloworld-client(新 grpc)の組み合わせで記述。
About gRPC
gRPC は Google 中心に開発された RPC フレームワークです。
Protocol Buffers でサービスとメッセージを定義し、HTTP/2 をトランスポートに、
unary(1 リクエスト → 1 レスポンス) から 双方向ストリーミング まで 使用可能。
JSON等、テキストベースの通信と比較して高速&データ量が小さいという特徴があります。
gRPC関連の用語は以下。
- Protocol Buffers(protobuf,
.proto): gRPC の IDL(インターフェイス定義言語) - tonic: Rust の gRPC 実装として事実上の標準
- prost: Rust 向け Protocol Buffers 実装
- channel / interceptor: gRPC クライアントが接続管理を担う抽象がchannel、リクエスト/レスポンスに介入するミドルウェアがinterceptor。
The Current State of gRPC-Rust
Preview Release
先日リリースされたv0.9の状況です。
公式 による説明は以下。
- Client API(unary / streaming すべて対応)
- Server API は まだリリースされていない
- 低レベル RPC API(インターセプタ、protobuf 生成コード非依存の RPC 実行)
- Google の Protobuf-Rust +
protocプラグインでコード生成 - 現在はTokio ランタイム専用(将来は複数ランタイム対応予定)
- "not recommended for production use at this time"
ロードマップ
ロードマップ では以下の内容が記述されています。
- In progress: サーバ API 開発、ヘルスチェック、メッセージ圧縮、gRPC Interop テストスイート
- Next up: リトライ、binary log、Channelz、keepalive、認可等
- Feature: メモリ削減・ゼロコピー
サーバ preview のリリース日は未公表ですが、次のマイルストーンに位置づけられてます。
About grpc-rust Repository
現在のリポジトリがどのようになっているか、
grpc/grpc-rust を GitHubで確認しました。
tonic と同居
リポジトリ直下の構成:
grpc/ 新公式 grpc(v0.9.0 preview)
grpc-protobuf/ grpc 用 protobuf-over-grpc 実装
grpc-protobuf-build/ grpc 用 protobuf build 統合
grpc-google/ well-known proto 型
protoc-gen-rust-grpc/ 新公式 grpc 用の protoc プラグイン
tonic/ ← tonic 本体(mature, v0.14.x)
tonic-build/, tonic-prost/・・・・
xds-client/, interop/, examples/
これまで hyperium/tonic にあったコードベースが
gRPC orgの公式りに統合され、新しい grpc クレートと同じワークスペースにいる状態です。
現在移行中かと思われます。
Sever側のコードはpub(crate) 状態
grpc/src/ を見ると、server/ ディレクトリはあります。
grpc/src/
├── attributes/
├── client/
│ ├── load_balancing/
│ ├── name_resolution/
│ └── transport/
│ └── tonic/
├── core/
├── credentials/
│ └── rustls/
│ ├── client/
│ └── server/ ← TLS server もある
├── metadata/
├── server/ ← 実装あり
│ ├── mod.rs
│ └── interceptor.rs
├── status/
│ └── server_status.rs
└── lib.rs
grpc/src/lib.rs の moduleをみると以下のように宣言されてます。
pub mod attributes;
pub mod client;
pub mod core;
pub mod credentials;
pub mod metadata;
pub(crate) mod inmemory;
pub(crate) mod server; // ← 公開してない
server は pub(crate) なので外部公開してませんが、
以下のようにすでにコードは存在し、PRもいくつか出てます。
pub struct Server { handler: Option<Arc<dyn DynHandle>> }
#[trait_variant::make(Send)]
pub trait Listener {
type SendStream: SendStream + 'static;
type RecvStream: RecvStream + 'static;
async fn accept(&self) -> Option<Call<Self::SendStream, Self::RecvStream>>;
}
impl Server {
pub fn new() -> Self { /* ... */ }
pub fn set_handler<H>(&mut self, h: H)
where H: Handle + Send + Sync + 'static { /* ... */ }
pub async fn serve(&self, l: &impl Listener) { /* ... */ }
}
もうしばらくすればpub になって公開されると思われます。
現在tonic を transport として使用
grpc/Cargo.toml の package.metadata.cargo_check_external_types を見ると、
allowed_external_types = [
"bytes::*",
"tonic::*", # ← 公的 API に tonic 型を露出することを許可
"futures_core::stream::Stream",
"tokio::sync::oneshot::*",
]
tonic::* が明示的に許可されています。そして grpc/src/client/transport/ ディレクトリには
tonic/ という transport モジュールがあります。
現在の grpc クレートは tonic を transport / async 基盤として使っています。
この統合の背景は、tonic 作者の Lucio Franco 氏自身が Tonic joins gRPC(2026-05-19) で以下のように説明しています。
- メンテナンスが "quite hard" になっていた
- 2024年、Doug Fawley 氏(Google gRPC チーム)と共にプロジェクト開始
- リポジトリは
hyperium/tonicからgrpc/grpc-rustに移管
公式 gRPC Welcomes Tonic は以下のように述べています。
"production-ready, long-term replacement for Tonic users"
"Tonic codegen interface will continue to be supported to
allow users to upgrade to the new transport implementation
without needing to rewrite their application"
"Tonic project will continue to operate as it did before"
新しい grpc が tonic ユーザーの長期的な移行先であり、コード生成インターフェイスは維持され、
書き換えなしで transport だけ差し替えられるよう設計される方針。
現時点ではtonic を内部基盤として活用しつつ、公式 gRPC 機能を被せて長期的な移行先を作るフェーズ
※将来 grpc クレートの transport が tonic 非依存になる可能性は残っていますが、公式 blog ではそこまで明示されていません
今後の方向性(公式: Client API Evolution)
新 grpc のクライアント API について、公式は Client API Evolution pt.1 と pt.2 で
その設計判断を解説しています。
HTTP/2 などトランスポート層の低レベルプリミティブを直接露出しない、
Arena メモリモデルや IntoFuture ベースの非同期ビルダーを採用する、
インターセプタはミドルウェア層に集約する、といった方向性で、
内部で tonic を使いつつも API レベルでは tonic とは別の設計に寄せている、
というのが大きな流れです。
ただ、pt.2で述べられているように「API にはまだ変更の余地があり、フィードバックを歓迎」とのこと。
grpc 0.9.0 はあくまで preview なので、本格的に使い始めるのはサーバ側 API が pub になり、
API が安定してからにするのが安全かと思われます。
V0.9でclient/server を動かせる?
| 構成 | クライアント | サーバ | 動かせるか |
|---|---|---|---|
新公式 grpc 0.9.0 のみ |
✅(public) | ❌(pub(crate)) |
不可 |
新 grpc(client)+ tonic(server) |
✅ | ✅ | 可 |
| tonic v0.14.x のみ | ✅ | ✅ | 可 |
gRPC は HTTP/2 + protobufで通信できるので、grpc の client と tonic の server なら現時点でも可能です。
公式のRust Quick Startではこの構成で動かしてます。
try grpc-rust & tonic
以下の環境で一応確認してみました。
- Rust 1.95.0
- protoc 34.1
- tonic 0.14.6
ワークスペース構成は以下。
grpc-rust-hello/
├── Cargo.toml
├── proto/
│ └── helloworld.proto
├── server/
│ ├── Cargo.toml
│ ├── build.rs
│ └── src/main.rs
└── client/
├── Cargo.toml
├── build.rs
└── src/main.rs
ルートの Cargo.toml は workspace 宣言(members = ["server", "client"] と共通 deps の集約)です。
※各クレートの依存は省略
proto
Greeter service に SayHello という unary RPCを定義した、
最小の proto ファイルです。
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
server
server/build.rs で、ビルド時に proto からサーバ側コードを生成します。
build_server(true).build_client(false) でサーバだけ出力させる指定。
あわせて、cargo:rerun-if-changed で .proto の編集を確実に拾い、
type_attribute で全メッセージに共通の derive を一括で入れています。
(ex.serde 連携で JSON に流したい時など)
use std::path::PathBuf;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let proto_dir = PathBuf::from("../proto");
// .proto を自動列挙
let protos: Vec<PathBuf> = std::fs::read_dir(&proto_dir)?
.filter_map(Result::ok)
.map(|e| e.path())
.filter(|p| p.extension().map(|e| e == "proto").unwrap_or(false))
.collect();
// proto 編集で必ず再生成
for p in &protos {
println!("cargo:rerun-if-changed={}", p.display());
}
println!("cargo:rerun-if-changed={}", proto_dir.display());
tonic_prost_build::configure()
.build_server(true)
.build_client(false)
// 全メッセージに serde を一括付与(必要なときだけ)
.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]")
.compile_protos(&protos, &[proto_dir])?;
Ok(())
}
生成物はデフォルトで OUT_DIR に置かれ、tonic::include_proto!("helloworld") で取り込めます。
.out_dir("src/generated") のようにカスタムパスを指定することもできますが、
その場合 include_proto! は使えなくなるので注意。
server/src/main.rs は tonic::include_proto! で生成コードを取り込み、
Greeter trait を MyGreeter に実装します。
SayHello が呼ばれたら受け取った name から "Hello, {name}!" を作成して返します。
use tonic::{transport::Server, Request, Response, Status};
pub mod helloworld {
tonic::include_proto!("helloworld");
}
use helloworld::greeter_server::{Greeter, GreeterServer};
use helloworld::{HelloReply, HelloRequest};
#[derive(Default)]
pub struct MyGreeter;
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
let name = request.into_inner().name;
Ok(Response::new(HelloReply {
message: format!("Hello, {name}! (from tonic server)"),
}))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "127.0.0.1:50051".parse()?;
println!("[server] Greeter listening on {addr}");
Server::builder()
.add_service(GreeterServer::new(MyGreeter))
.serve(addr)
.await?;
Ok(())
}
client
client/build.rs も同じ proto を読みますが、
build_server(false).build_client(true) でクライアント側のコードだけ生成します。
中身は server 側とほぼ対称で、
cargo:rerun-if-changed や type_attribute も同じように記述します。
use std::path::PathBuf;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let proto_dir = PathBuf::from("../proto");
let protos: Vec<PathBuf> = std::fs::read_dir(&proto_dir)?
.filter_map(Result::ok).map(|e| e.path())
.filter(|p| p.extension().map(|e| e == "proto").unwrap_or(false))
.collect();
for p in &protos {
println!("cargo:rerun-if-changed={}", p.display());
}
println!("cargo:rerun-if-changed={}", proto_dir.display());
tonic_prost_build::configure()
.build_server(false)
.build_client(true)
.compile_protos(&protos, &[proto_dir])?;
Ok(())
}
client/src/main.rs は say_hello() を呼び出してます。
pub mod helloworld {
tonic::include_proto!("helloworld");
}
use helloworld::greeter_client::GreeterClient;
use helloworld::HelloRequest;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://127.0.0.1:50051").await?;
let resp = client
.say_hello(tonic::Request::new(HelloRequest { name: "tonic-client".into() }))
.await?;
println!("[client] RESPONSE: {}", resp.into_inner().message);
Ok(())
}
実行
cargo build --release で両方ビルドした後、サーバをバックグラウンドで起動し、
クライアントを叩くと以下のようになります。
$ cargo build --release
...
Finished `release` profile [optimized] target(s) in 51.09s
$ ./target/release/server &
[server] Greeter listening on 127.0.0.1:50051
$ ./target/release/client
[client] RESPONSE: Hello, tonic-client! (from tonic server)
.proto 1 ファイルから、tonic がサーバ / クライアント両方の bindings を生成し、
gRPC over HTTP/2 で通信できました。
Summary
公式 grpc 0.9.0 はクライアントだけが public で、
サーバはコードがリポジトリに既にあるものの pub(crate) で外部には出ていません。
現状でclient / server を動かしたい場合はtonic v0.14.x を使いましょう。
公式は新 grpc クレートを Tonic users の long-term replacement と位置づけており、
現 preview の内部実装も tonic を transport として使っています。
codegen interface は維持される方針なので、サーバ側 API が公開されたあとは、
tonic で組んだものを丸ごと書き直すのではなく、transportレイヤの差し替えで済みそうです。
References
- gRPC-Rust Roadmap | gRPC blog(2026-06-02)
- gRPC-Rust Client API Evolution (pt. 2/2) | gRPC blog(2026-06-01)
- gRPC-Rust Client API Evolution (pt. 1/2) | gRPC blog(2026-05-29)
- gRPC-Rust Preview Release | gRPC blog(2026-05-28)
- gRPC Welcomes Tonic | gRPC blog(2026-05-21)
- Tonic joins gRPC | Lucio Franco's Blog(2026-05-19)
- Rust Quick Start | gRPC Docs
- grpc-rust PR #2619: tonic-xds gRFC A50 outlier detection(2026-06-03 マージ)
- crates.io: grpc
- gRPC 公式
- GitHub: grpc/grpc-rust








