gRPC
By the Syncfusion DevTutorials team · Last updated
Let services talk fast with small binary protobuf messages and a strict .proto contract.
gRPC is an API style designed for communication between services.
Instead of sending JSON text, gRPC sends compact binary messages encoded using Protocol Buffers (protobuf). Both the client and server agree on the structure of every message through a shared contract file called a .proto file. Because the message format is predefined, gRPC can send data more efficiently than JSON and is commonly used for communication between internal services.
Watch an Internal Call Carry Its Own Labels
As Brew & Bytes grows, the Order Service no longer processes payments itself. Instead, it calls a separate Payment Service. The services currently communicate using JSON. Press Run.
Program.cs — an internal JSON endpoint
Notice the response size:
X-Body-Bytes: 87
Much of the message consists of field names:
{
"paymentId": "...",
"currency": "INR",
"status": "approved"
}
The Payment Service already knows these field names. The Order Service already knows these field names. Transmitting the same labels repeatedly is unnecessary work.
In simple words: JSON repeatedly sends field names. gRPC sends compact binary data because both sides already know the structure.
TL;DR
- gRPC uses Protocol Buffers (protobuf).
- Messages are encoded as compact binary bytes.
- The
.protofile defines the contract. - Field names are never sent across the network.
- Every field has a unique field number.
- Small numbers use very little space through varint encoding.
- Never change or reuse field numbers.
- Removed field numbers should be marked as
reserved. - gRPC runs on HTTP/2.
gRPC supports:
- Unary calls
- Streaming
- gRPC is best suited for internal service-to-service communication.
- Browsers typically require gRPC-Web rather than raw gRPC.
A Real-World Example
Imagine restaurant staff communicating inside a busy kitchen. A waiter could write:
Dear kitchen,
Please prepare two lattes for table four.
Thank you.
This contains a lot of unnecessary text. Instead, kitchens often use shorthand:
T4 2xLAT
Everyone already understands the notation. It is faster to write and faster to read. The .proto file is the shared codebook. The protobuf message is the shorthand note.
JSON spends many bytes on field names and punctuation. Protobuf sends only field identifiers and values.
What You Will Learn
In this lesson, you will learn:
- Why gRPC is efficient for internal communication.
- How
.protocontracts work. - How protobuf encodes data into bytes.
- How protobuf decodes bytes back into values.
- How to safely evolve a contract.
- How unary and streaming calls differ.
What runs here, and what does not. gRPC needs HTTP/2 and generated code, and neither can run in this browser. So the cells below do the part that can run: they build and read real protobuf bytes by hand. The bytes are exactly what the official protobuf library produces for the same message. The HTTP/2 transport and the generated client and server classes are shown as read-only code. No cell here makes a real gRPC call.
The Contract: A .proto File
Every gRPC application starts with a .proto file.
Example:
syntax = "proto3";
package brew.payments;
message PaymentRequest {
int32 order_id = 1;
int32 amount = 2;
string currency = 3;
}
message PaymentReply {
string payment_id = 1;
string status = 2;
}
message StatusRequest {
int32 order_id = 1;
}
message StatusUpdate {
int32 order_id = 1;
string status = 2;
}
service PaymentService {
rpc Charge (PaymentRequest)
returns (PaymentReply);
rpc GetStatus (StatusRequest)
returns (StatusUpdate);
rpc WatchStatus (StatusRequest)
returns (stream StatusUpdate);
}
Field Numbers
Consider:
int32 order_id = 1;
The value:
= 1
is the field number.
It is not a default value.
Field numbers identify fields on the wire.
Example:
order_id = 1
amount = 2
currency = 3
Only these numbers are transmitted.
The field names never travel across the network.
Service Definitions
A service acts much like a collection of endpoints.
Example:
service PaymentService {
rpc Charge (...)
}
The Charge RPC behaves similarly to a REST endpoint but uses protobuf messages instead of JSON.
Encode a Message into Bytes
Suppose we create:
{
"orderId": 101,
"amount": 440,
"currency": "INR"
}
In protobuf, each field is stored as: Tag + Value.
The tag contains:
Field Number
+
Wire Type
Formula:
(field_number << 3) | wire_type
Encode.cs — PaymentRequest to bytes
order_id = 101
Tag: 08
Value: 65
amount = 440
Tag: 10
Value: B8 03
currency = "INR"
Tag: 1A
Length: 03
Bytes: 49 4E 52
Total protobuf size: 10 bytes
Equivalent JSON: 45 bytes
The savings become significant when millions of messages are exchanged.
Decode Bytes Back into Data
Decoding performs the reverse process.
The reader:
- Reads a tag.
- Extracts the field number.
- Determines the wire type.
- Reads the value.
Decode.cs — bytes back to fields
Result:
Field 1 → 101
Field 2 → 440
Field 3 → INR
Notice that the bytes never store:
order_id
amount
currency
The .proto file provides those meanings. Without the contract, the data cannot be interpreted correctly.
In proto3, fields with default values are often omitted from the message.
For example:
int32 points = 0;
may not be transmitted at all.
If your application must distinguish between 0 and Not provided
use:
optional
fields.
Evolving the Contract Safely
Field numbers are permanent. Changing their meaning can produce silent data corruption. Consider this change:
Original:
int32 amount = 2;
Updated:
int32 discount = 2;
int32 amount = 4;
Old services still interpret field:
2
as:
amount
Renumber.cs — a reused field number
Result: amount = 40
instead of: amount = 440
No exception occurs. No validation error appears. The payment service silently processes the wrong value.
Never change or reuse a field number. Field numbers are part of the public contract.
Safe Removal
When removing a field:
message PaymentRequest {
reserved 2;
reserved "amount_old";
int32 order_id = 1;
string currency = 3;
int32 amount = 4;
int32 discount = 5;
}
Now field number 2 can never be reused accidentally.
Safe Changes
Safe contract changes include:
- Adding a new field with a new number
- Reserving removed fields
- Adding new messages
- Adding new service methods
Unsafe changes include:
- Reusing field numbers
- Changing field meaning
- Renumbering fields
Unary and Streaming Calls
gRPC supports multiple communication patterns.
Unary Calls
One request. One response.
Example:
- Client → Charge
- Server → PaymentReply
This works much like a traditional REST request.
Server Streaming
One request. Many responses.
Example:
Client → WatchStatus
Server → received
Server → preparing
Server → ready
The connection remains open while updates arrive.
Stream.cs — unary and streaming frames
Streaming avoids repeated polling and supports real-time updates efficiently.
gRPC Framing
Each protobuf message is placed inside a gRPC frame.
Frame structure:
1 byte Compression Flag
4 bytes Message Length
N bytes Message Data
Example:
00 00 00 00 0D
means:
Not compressed
13-byte message follows
Streaming simply sends multiple frames on the same HTTP/2 connection.
Real gRPC in ASP.NET Core
A real server typically looks like:
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<PaymentService>();
app.Run();
Generated classes come directly from the .proto contract. The implementation focuses only on business logic.
public override Task<PaymentReply> Charge(
PaymentRequest request,
ServerCallContext context)
{
return Task.FromResult(
new PaymentReply
{
PaymentId = $"pay-{request.OrderId}",
Status = "approved"
});
}
The framework handles:
- Serialization
- Deserialization
- HTTP/2 transport
- Generated client code
REST vs gRPC
| Feature | REST | gRPC |
|---|---|---|
| Format | JSON | Protocol Buffers |
| Readability | Human-readable | Binary |
| Message Size | Larger | Smaller |
| Browser Support | Excellent | Requires gRPC-Web |
| Public APIs | Excellent | Rare |
| Internal Services | Good | Excellent |
| Streaming | Limited | Built-in |
| Contract | Optional | Required (.proto) |
When to Use gRPC
gRPC is a strong choice when:
- Both client and server are owned by your organization.
- Performance matters.
- Services communicate frequently.
- Strong contracts are important.
- Streaming is required.
When REST Is Better
REST is usually a better choice when:
- External developers consume the API.
- Requests are inspected frequently.
- Browser compatibility is important.
- Simplicity is preferred.
REST is ideal for public APIs. gRPC is ideal for internal service communication.
Where You See This
- Large microservice architectures use gRPC between services.
- Google Cloud services heavily rely on gRPC.
- Kubernetes components communicate using gRPC.
- Many .NET teams use
Grpc.AspNetCore. - JavaScript and TypeScript teams often use
@grpc/grpc-jsor Connect.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| Services interpret values incorrectly after deployment | A field number was changed or reused | Never reuse field numbers; reserve removed ones |
| Browser requests fail | Browsers cannot use raw gRPC directly | Use gRPC-Web or a REST gateway |
A real value of 0 is treated as missing | Default proto3 behavior | Use optional fields |
| Services disagree about message formats | Different .proto versions are deployed | Share one contract and regenerate clients |
| Messages are larger than expected | JSON is used for high-volume internal traffic | Switch internal service calls to gRPC |
| Status updates require repeated polling | Unary calls are used for live updates | Use gRPC streaming |
Exercises
What to Remember
- gRPC sends small binary protobuf messages. The
.protofile is the shared contract. - Each field is a tag plus a value.
tag = (field_number << 3) | wire_type. Names never travel. - Numbers are varints: 7 bits in each byte, and the top bit means "more bytes follow".
- Never reuse a field number. Add new numbers, and
reservethe removed ones. Old readers skip unknown fields safely. - gRPC supports unary and streaming calls over HTTP/2. Each message gets a 5-byte frame header.
- Use REST for public and browser callers, and use gRPC between your own services.
Next: REST vs GraphQL vs gRPC. You will put the three styles side by side, and you will learn how to pick the right one for each job.