REST uses JSON over HTTP. It’s human-readable, widely supported, and great for public APIs. But when two microservices are talking to each other thousands of times per second inside our data center, we don’t need human-readability. We need speed. That’s where gRPC comes in.
What Is gRPC?
gRPC (gRPC Remote Procedure Calls) is an open-source framework created by Google. It lets services call methods on other services as if they were local function calls. Under the hood, it uses HTTP/2 for transport and Protocol Buffers (protobuf) for serialization.
In simple language, instead of crafting HTTP requests with URLs and JSON, we just call orderService.createOrder(orderData) and gRPC handles the networking.
Protocol Buffers (Protobuf)
Protobuf is a binary serialization format. We define our data structure in a .proto file, and protobuf generates code in any language.
// user.proto
syntax = "proto3";
package userservice;
message User {
int32 id = 1;
string name = 2;
string email = 3;
repeated string roles = 4;
}
message GetUserRequest {
int32 id = 1;
}
message GetUserResponse {
User user = 1;
}
service UserService {
rpc GetUser(GetUserRequest) returns (GetUserResponse);
rpc CreateUser(User) returns (User);
rpc ListUsers(ListUsersRequest) returns (stream User);
}
The numbers (= 1, = 2) are field tags — they identify fields in the binary format and should never be changed once deployed.
Why Binary?
JSON is text-based. A number like 12345 is 5 characters (5 bytes). In protobuf, it’s a variable-length integer — just 2 bytes. At millions of requests per second, those savings add up.
| Format | Size (typical) | Parse Speed | Human Readable |
|---|---|---|---|
| JSON | Larger | Slower | Yes |
| Protobuf | 3-10x smaller | 5-100x faster | No |
| XML | Largest | Slowest | Yes |
How gRPC Works
- We define our service and messages in a
.protofile - The protobuf compiler (
protoc) generates client and server code in our language - The server implements the service methods
- The client calls those methods like regular functions
- gRPC handles serialization, HTTP/2 transport, and error handling
Client Server
│ │
│ orderService.CreateOrder() │
│ ──── protobuf bytes ────→ │
│ over HTTP/2 │
│ │ → executes CreateOrder()
│ ←──── protobuf bytes ──── │
│ (response) │
We never manually construct HTTP requests or parse JSON. The generated code handles everything.
Four Communication Patterns
1. Unary RPC (Request-Response)
Like a regular function call. Client sends one request, server sends one response.
rpc GetUser(GetUserRequest) returns (GetUserResponse);
This is the most common pattern. Same as a REST API call but faster.
2. Server Streaming
Client sends one request, server sends back a stream of responses.
rpc ListUsers(ListUsersRequest) returns (stream User);
Great for: fetching large datasets incrementally, real-time event feeds, live logs.
3. Client Streaming
Client sends a stream of requests, server sends one response when the client is done.
rpc UploadChunks(stream FileChunk) returns (UploadResult);
Great for: file uploads, sending sensor data, batch operations.
4. Bidirectional Streaming
Both sides send streams of messages simultaneously. Like a WebSocket conversation but with typed messages.
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
Great for: chat systems, collaborative editing, real-time gaming.
gRPC vs REST
| Aspect | REST | gRPC |
|---|---|---|
| Protocol | HTTP/1.1 (usually) | HTTP/2 (always) |
| Format | JSON (text) | Protobuf (binary) |
| Speed | Good | 2-10x faster |
| Payload size | Larger | 3-10x smaller |
| Streaming | Limited (SSE, WebSocket) | Built-in (4 patterns) |
| Code generation | Optional (OpenAPI) | Required (proto files) |
| Browser support | Native | Needs grpc-web proxy |
| Schema | Optional (OpenAPI/Swagger) | Required (proto files) |
| Caching | Easy (HTTP caching) | Hard |
| Human debugging | Easy (read JSON) | Hard (binary data) |
| Learning curve | Low | Medium-High |
When to Use gRPC
Use gRPC for:
- Microservice-to-microservice communication inside our infrastructure
- High-throughput services where performance matters (10,000+ RPS)
- Polyglot environments — proto files generate code for Go, Java, Python, C++, etc.
- Streaming use cases — server streaming, bidirectional streaming
- Mobile clients — smaller payloads = less bandwidth on cellular networks
Stick with REST for:
- Public APIs — REST is universally understood, gRPC needs protobuf knowledge
- Browser clients — browsers can’t make native gRPC calls (need grpc-web proxy)
- Simple CRUD — the overhead of proto files isn’t worth it for basic operations
- Debugging — we can’t just curl a gRPC endpoint and read the response
HTTP/2 Advantages
gRPC uses HTTP/2, which gives us:
- Multiplexing — Multiple RPC calls over a single TCP connection. No head-of-line blocking.
- Header compression — HTTP/2 compresses headers with HPACK, reducing overhead on repeated calls.
- Binary framing — More efficient than HTTP/1.1 text parsing.
In REST over HTTP/1.1, each request needs its own TCP connection (or waits in a queue). In gRPC over HTTP/2, we multiplex hundreds of concurrent calls on one connection.
Error Handling
gRPC uses its own status codes (similar to HTTP but different):
| gRPC Code | Meaning | Similar HTTP |
|---|---|---|
OK | Success | 200 |
NOT_FOUND | Resource doesn’t exist | 404 |
ALREADY_EXISTS | Duplicate | 409 |
PERMISSION_DENIED | Not authorized | 403 |
UNAVAILABLE | Service is down | 503 |
DEADLINE_EXCEEDED | Timeout | 408 |
INTERNAL | Server error | 500 |
gRPC also has built-in deadlines. Every call can specify a timeout, and if the server doesn’t respond in time, the call fails with DEADLINE_EXCEEDED. This prevents hanging calls.
Key Takeaway
In simple language, gRPC is a faster alternative to REST that uses binary data (protobuf) instead of JSON and HTTP/2 instead of HTTP/1.1. It’s ideal for communication between microservices where speed and efficiency matter more than human-readability. The proto file serves as both the API contract and the source for auto-generated client/server code. Use gRPC internally between services, REST externally for public APIs. Many large systems (Google, Netflix, Square) use both — gRPC inside, REST outside.