Skip to main content
Version: 5.1

gRPC Tool

The bal grpc tool generates Ballerina code from Protocol Buffer (.proto) files. It creates service stubs with RPC method signatures, client connectors for calling gRPC services, and Ballerina record types that correspond to protobuf message definitions. This lets you integrate with gRPC-based microservices using idiomatic Ballerina code.

note

gRPC code generation is not available through the Visual Designer. The + Add Artifact menu does not include a gRPC option. Use the integrated terminal in your project to run bal grpc commands directly.


Example proto file​

The examples throughout this page use the following proto file:


syntax = "proto3";

package orders;

service OrderService {
rpc GetOrder (GetOrderRequest) returns (Order);
rpc CreateOrder (CreateOrderRequest) returns (Order);
rpc ListOrders (ListOrdersRequest) returns (stream Order);
rpc UploadOrders (stream CreateOrderRequest) returns (Order);
rpc StreamUpdates (stream OrderUpdate) returns (stream StatusUpdate);
}

message GetOrderRequest {
string order_id = 1;
}

message CreateOrderRequest {
string customer_id = 1;
repeated LineItem items = 2;
}

message LineItem {
string product_id = 1;
int32 quantity = 2;
double unit_price = 3;
}

message Order {
string id = 1;
string customer_id = 2;
repeated LineItem items = 3;
double total = 4;
OrderStatus status = 5;
}

message OrderUpdate {
string order_id = 1;
OrderStatus new_status = 2;
}

message StatusUpdate {
string order_id = 1;
OrderStatus status = 2;
}

message ListOrdersRequest {
string customer_id = 1;
int32 limit = 2;
}

enum OrderStatus {
PENDING = 0;
CONFIRMED = 1;
SHIPPED = 2;
DELIVERED = 3;
CANCELLED = 4;
}

Generating a service stub from a proto file​

Use this when you want to expose a gRPC service from your integrator project.

note

The generated service and client file names are derived from the service name in the proto file. For service OrderService in order_service.proto, the tool generates orderservice_service.bal and orderservice_client.bal.

Step 1: Place the proto file in your project​

Copy your .proto file into a resources/ folder inside your integrator project:

my-integration/
├── Ballerina.toml
├── main.bal
└── resources/
└── order_service.proto

Step 2: Open the terminal at the project root​

In the editor, open the integrated terminal (Ctrl+`) and confirm you are in the project root, the directory that contains Ballerina.toml:

ls Ballerina.toml

Step 3: Run the tool​

bal grpc --input resources/order_service.proto --mode service --output .

Step 4: Verify generated files​

The tool places two files in the project root:

my-integration/
├── Ballerina.toml
├── main.bal
├── resources/
│ └── order_service.proto
├── order_service_pb.bal # Message types (records)
└── orderservice_service.bal # Service stub with empty RPC methods

Both files are compiled automatically as part of the project package, with no extra imports or configuration needed.

Step 5: Implement the service​

Open orderservice_service.bal and fill in the generated stub methods with your integration logic:

import ballerina/grpc;

listener grpc:Listener ep = new (9090);

@grpc:Descriptor {value: ORDER_SERVICE_DESC}
service "OrderService" on ep {

remote function GetOrder(GetOrderRequest request) returns Order|error {
// TODO: Implement
}

remote function CreateOrder(CreateOrderRequest request) returns Order|error {
// TODO: Implement
}

remote function ListOrders(ListOrdersRequest request) returns stream<Order, error?>|error {
// TODO: Implement
}

remote function UploadOrders(stream<CreateOrderRequest, grpc:Error?> clientStream) returns Order|error {
// TODO: Implement
}

remote function StreamUpdates(stream<OrderUpdate, grpc:Error?> clientStream) returns stream<StatusUpdate, error?>|error {
// TODO: Implement
}
}


Generating a client from a proto file​

Use this when you want to call an external gRPC service from your integrator project.

Step 1: Place the proto file in your project​

my-integration/
├── Ballerina.toml
├── main.bal
└── resources/
└── order_service.proto

Step 2: Open the terminal at the project root​

ls Ballerina.toml

Step 3: Run the tool​

bal grpc --input resources/order_service.proto --mode client --output .

Step 4: Verify generated files​

my-integration/
├── Ballerina.toml
├── main.bal
├── resources/
│ └── order_service.proto
├── order_service_pb.bal # Message types (records)
└── orderservice_client.bal # Type-safe client connector

Step 5: Use the client in your integration​

Open the existing connections.bal file in your project root and add the client initialisation. This makes the client available as a module-level variable across all flows and artifacts:

my-integration/
├── Ballerina.toml
├── main.bal
├── connections.bal ← open this file
├── resources/
│ └── order_service.proto
├── order_service_pb.bal
└── orderservice_client.bal

In connections.bal:

configurable string orderServiceUrl = ?;

final OrderServiceClient orderClient = check new (orderServiceUrl);

Add the service URL to your Config.toml:

orderServiceUrl = "http://localhost:9090"

Unary RPC:

function getOrder(string orderId) returns Order|error {
return check orderClient->GetOrder({order_id: orderId});
}

function createOrder(string customerId, LineItem[] items) returns Order|error {
return check orderClient->CreateOrder({
customer_id: customerId,
items: items
});
}

Server streaming:

function listCustomerOrders(string customerId) returns Order[]|error {
stream<Order, error?> orderStream = check orderClient->ListOrders(
{customer_id: customerId, 'limit: 50}
);
Order[] orders = [];
check orderStream.forEach(function(Order 'order) {
orders.push('order);
});
return orders;
}

Bidirectional streaming:

function streamOrderUpdates(OrderUpdate[] updates) returns StatusUpdate[]|error {
StreamUpdatesStreamingClient streamClient = check orderClient->StreamUpdates();
foreach OrderUpdate update in updates {
check streamClient->sendOrderUpdate(update);
}
check streamClient->complete();

StatusUpdate[] statuses = [];
StatusUpdate|grpc:Error? response = streamClient->receiveStatusUpdate();
while response is StatusUpdate {
statuses.push(response);
response = streamClient->receiveStatusUpdate();
}
if response is grpc:Error {
return response;
}
return statuses;
}

Generating only the stub file​

Omit --mode to generate only the stub file:

bal grpc --input resources/order_service.proto --output .

This produces only the order_service_pb.bal file (message types and the descriptor constant). No service or client file is generated.


Proto import paths​

If your proto file imports other proto files, use --proto-path to tell the tool where to resolve them. The directory you pass must contain the input .proto file, and imports are resolved relative to it:

bal grpc --input resources/order_service.proto \
--proto-path resources \
--output .
note

The flag is spelled --proto-path (with a hyphen); --proto_path is rejected. Pass the directory without a leading ./ or trailing /, and make sure it encompasses the input file, otherwise the tool fails with Input .proto file does not reside within the path specified using --proto-path.


Regenerating after proto changes​

Re-run the same command whenever the .proto file changes. The generated files are overwritten automatically.

Do not edit order_service_pb.bal directly. It is always overwritten on regeneration. Put all custom logic in separate files.


Command reference​

bal grpc --input <proto-file> [options]
FlagAliasRequiredDefaultDescription
--input—Yes—Path to a .proto file, or a directory containing multiple .proto files
--output—NoDirectory named after the proto package (or temp if no package is declared)Output directory for generated files
--mode—No—client or service to also generate sample code. If omitted, only the stub file (*_pb.bal) is generated
--proto-path—No—Directory used to resolve import statements. It must contain the input .proto file

Protobuf to Ballerina type mapping​

Protobuf typeBallerina type
doublefloat
floatfloat
int32, sint32, sfixed32int
int64, sint64, sfixed64int
uint32, fixed32int
uint64, fixed64int
boolboolean
stringstring
bytesbyte[]
enumenum
messagerecord {}
repeated TT[]
map<K, V>map<V>
oneofUnion type
google.protobuf.Anyanydata
google.protobuf.Timestamptime:Utc
google.protobuf.Durationdecimal
google.protobuf.Structmap<anydata>

gRPC communication patterns​

PatternProto definitionBallerina signature
Unaryrpc Method(Req) returns (Res)remote function Method(Req) returns Res|error
Server streamingrpc Method(Req) returns (stream Res)remote function Method(Req) returns stream<Res, error?>|error
Client streamingrpc Method(stream Req) returns (Res)remote function Method(stream<Req, error?>) returns Res|error
Bidirectionalrpc Method(stream Req) returns (stream Res)remote function Method(stream<Req, error?>) returns stream<Res, error?>|error

What's next​