TL;DR: Tonic is an async gRPC framework for Rust built on Tokio and Hyper. You define services in
.protofiles, usetonic-buildinbuild.rsto generate Rust types and traits, then implement the generated service trait. Tonic supports all four gRPC call types: unary, server-streaming, client-streaming, and bidirectional streaming. It integrates with Tower middleware for interceptors, auth, and retries.
What Is gRPC?
gRPC is a high-performance RPC framework that uses Protocol Buffers for serialization and HTTP/2 for transport.
It is the standard choice for service-to-service communication in microservice architectures; particularly at companies like Google, Uber, and Netflix. Benefits over REST: strong typing, code generation, streaming support, and ~5–10× smaller payloads vs JSON.
How Do You Define a gRPC Service With Tonic?
Write a .proto file, generate Rust code with tonic-build, then implement the service trait.
// proto/hello.proto
syntax = "proto3";
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }# Cargo.toml
[dependencies]
tonic = "0.12"
prost = "0.13"
tokio = { version = "1", features = ["full"] }
[build-dependencies]
tonic-build = "0.12"// build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos("proto/hello.proto")?;
Ok(())
}How Do You Implement the Server?
Implement the generated trait and serve it with tonic::transport::Server.
use tonic::{transport::Server, Request, Response, Status};
use hello::greeter_server::{Greeter, GreeterServer};
use hello::{HelloReply, HelloRequest};
pub mod hello {
tonic::include_proto!("hello");
}
#[derive(Default)]
struct GreeterService;
#[tonic::async_trait]
impl Greeter for GreeterService {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
let reply = HelloReply {
message: format!("Hello, {}!", request.into_inner().name),
};
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
Server::builder()
.add_service(GreeterServer::new(GreeterService::default()))
.serve("0.0.0.0:50051".parse()?)
.await?;
Ok(())
}Tonic vs Axum vs Actix in 2026
Tonic is for internal service-to-service RPC; Axum and Actix-web are for public-facing HTTP APIs; they solve different problems.
| Tonic (gRPC) | Axum (REST) | Actix-web (REST) | |
|---|---|---|---|
| Serialization | Protocol Buffers | JSON (serde) | JSON (serde) |
| Transport | HTTP/2 | HTTP/1.1 or 2 | HTTP/1.1 or 2 |
| Strong typing | ✅ Generated from proto | Manual | Manual |
| Browser-friendly | ❌ (needs grpc-web) | ✅ | ✅ |
| Streaming | ✅ Native (4 modes) | Limited (SSE) | Limited (SSE) |
| Middleware | Tower layers | Tower layers | Custom actors |
| Maintainer | hyperium org | Tokio team | actix org |
| Best for | Microservices, internal APIs | Public APIs, web backends | High-throughput web APIs |
In 2026, the most common pattern is pairing Tonic for internal gRPC between microservices with Axum as the public-facing HTTP gateway. If you are building a single service that only talks to browsers, choose Axum or Actix-web. If you are designing a backend cluster where services call each other directly, Tonic's generated types and streaming capabilities pay off quickly.
Frequently Asked Questions
Yes. Server::builder().layer(my_layer) applies Tower middleware to all services. Common uses: authentication interceptors, rate limiting, and tracing with tower-http.
Technically yes, but it is non-standard. Tonic's code generation is tightly coupled to prost (the Rust protobuf library). For schema-free RPC, consider a REST or GraphQL framework instead.
Use tonic::transport::ServerTlsConfig and provide certificate and key files. The Tonic docs have a full TLS example with self-signed certs for development.
Tonic 0.12.x is the current stable release, paired with prost 0.13 and Tokio 1.x. The tonic-build version must match your tonic dependency version exactly.
Yes; all four gRPC call types are supported: unary, server-streaming, client-streaming, and bidirectional streaming. Declare the streaming mode in the .proto file using the stream keyword.
Sources
- tonic on crates.io
- Tonic GitHub; hyperium/tonic
- gRPC official docs
- prost; Rust Protocol Buffers implementation
Related Glossary Terms
- tokio: The async runtime Tonic is built on
- axum: HTTP REST framework, the complement to Tonic
- tower: Middleware layer system Tonic uses for interceptors
- hyper: Low-level HTTP library underlying Tonic's transport
- serde: Used in REST APIs; contrast with protobuf in Tonic
- rustls: Production Tonic deployments commonly use rustls for TLS on gRPC services
- Tracing: Structured tracing is standard practice in gRPC middleware and service observability
Keep Reading
- Rust Backend Frameworks Compared: Tonic vs Axum vs Actix for different use cases
- Rust vs Go in 2026: Which language wins for microservices in 2026

