Eliminate gRPC Boilerplate in Ballerina: From .proto to Running Service in Minutes
Ballerina’s native gRPC connector turns a single .proto file into fully typed client and server stubs, eliminating boilerplate and keeping your service definition in sync with the API contract. Learn how to generate, implement, and test a gRPC service in minutes.
08 Jul 2025, 01:04 UTC

Problem: The Boilerplate Burden of gRPC in Microservices
Modern microservices often communicate via gRPC because it offers HTTP/2 transport, binary serialization, and language‑agnostic contracts. However, the typical workflow—writing a .proto file, generating stubs, wiring them into a framework, and handling type conversions—creates a lot of repetitive code. In Java, for instance, you end up with generated Java classes, a Spring or Vert.x controller, and manual mapping between protobuf messages and domain objects. The result is a maintenance overhead that slows down iteration and increases the chance of contract drift.
Thesis: Ballerina’s Built‑in gRPC Connector Automates the Entire Pipeline
Ballerina ships a native gRPC connector that turns a single .proto into fully typed client and server stubs, validates payloads at compile time, and bundles everything into a Docker image ready for Kubernetes. This eliminates boilerplate, keeps the service definition in sync with the API contract, and lets developers focus on business logic.
How It Works: From .proto to a Running Service
- Define the contract. Create a
service.protofile that describes your RPCs. Ballerina supports all four gRPC patterns: unary, client‑streaming, server‑streaming, and bidirectional streaming. - Generate Ballerina code. Run
bal grpc --proto service.protofrom the project root. The tool generates two packages:service_pb– the protobuf message types.service_grpc– the service interface and stub classes.
- Implement the service. Create a
service.balfile that implements the generated interface. Because the generated types are native Ballerina types, you can validate fields at compile time and avoid runtime type errors. - Run and test. Compile with
bal runand usegrpcurlto call the service. The generated Docker image can be pushed to a registry and deployed to Kubernetes with an automatically generated Helm chart.
Concrete Example
Below is a minimal end‑to‑end example that demonstrates each step. Replace <PLACEHOLDER> with your own values when you try it out.
# service.proto
syntax = "proto3";
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
# Generate Ballerina code
bal grpc --proto service.proto
# service.bal
import ballerina/grpc;
import hello.*; // imports service_pb and service_grpc
service /hello on port 9090 {
resource function greeter.sayHello(HelloRequest req) returns HelloReply {
log:printInfo("Received: " + req.name);
return HelloReply { message: "Hello, " + req.name + "!" };
}
}
# Run the service
bal run
# Test with grpcurl
grpcurl -plaintext localhost:9090 list
# Expected output:
# hello.Greeter
grpcurl -plaintext -d '{"name":"World"}' localhost:9090 hello.Greeter/SayHello
# Expected output:
# {"message":"Hello, World!"}
Trade‑Off: Missing Advanced Features
While the connector covers the core gRPC patterns, it currently lacks support for features that are common in production environments:
- Interceptors – you cannot plug in cross‑cutting concerns (e.g., tracing, authentication) via the connector API.
- Custom metadata handling – adding or inspecting HTTP/2 metadata requires manual code.
- gRPC‑web integration – serving browsers directly through gRPC‑web is not yet supported.
If your application relies heavily on these features, you may need to extend the generated code manually or combine Ballerina with a Java gRPC library.
Actionable Next Steps
- Start a new Ballerina project with
bal new grpc-demoand copy the example above. - Experiment with streaming RPCs by adding a
streaming HelloRequest to HelloReplyRPC in the.protofile. - Package the service with
bal pack, push the image to a registry, and deploy to a Kubernetes cluster using the generated Helm chart. - If you need interceptors, consider writing a custom Ballerina module that wraps the generated client or server, or migrate to a hybrid approach where Ballerina handles the transport and a Java gRPC library handles advanced features.
With Ballerina’s gRPC connector, you can cut down the amount of boilerplate code from dozens of lines to a handful of declarative statements, keeping your service definitions tightly coupled to your API contracts and making your microservice lifecycle faster and more reliable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.