As microservices become the backbone of modern backend architecture, efficient communication between services becomes more critical. In this post, we’ll explore how gRPC fits into the picture and how you can get started with it using Spring Boot.
🧠 What is gRPC and Why Use It?
gRPC is a modern, open-source, high-performance Remote Procedure Call (RPC) framework created by Google.
But what does that mean in simple words?
- Imagine calling a method of a class that’s located in a different server or system — that’s what gRPC lets you do.
🟢 Key Features of gRPC:
-
Uses Protocol Buffers (Protobuf) — a fast and compact data format
-
Supports multiple programming languages (Java, Go, Python, etc.)
-
Enables contract-first development using
.proto
files -
Offers streaming (server, client, and bi-directional)
-
Built-in support for authentication, load balancing, and deadlines
🔄 gRPC vs REST — What’s the Difference?
🧰 How Spring Boot Supports gRPC
Out of the box, Spring Boot doesn’t have native gRPC support, but the community provides great libraries like:
-
yidongnan/grpc-spring-boot-starter
– most popular starter library -
LogNet/grpc-spring-boot-starter
– another alternative
These libraries let you:
-
Create gRPC services using
@GRpcService
-
Register interceptors
-
Inject Spring-managed beans into gRPC services
-
Easily manage service discovery, security, and observability
🔍 When to Use gRPC?
1️⃣ You Need Low Latency, High Throughput Communication
Use Case: Financial trading platforms, ad bidding systems
Example: A trading engine uses gRPC to execute millions of trades per second with sub-ms latency.
2️⃣ You’re Working with Polyglot Microservices
Use Case: Cross-language service communication
Example: A Python-based ML model communicates with a Java order service via gRPC using Protobuf contracts.
3️⃣ You Want Real-Time Communication
Use Case: Chat, live dashboards, game backends, telemetry
Example: A ride-sharing app streams driver location updates to the user’s device using server-streaming gRPC.
4️⃣ You Need Full-Duplex Streaming (Bi-directional)
Use Case: Video conferencing, collaborative editing, WebRTC control channels
Example: A video conferencing tool uses gRPC for signaling between peers and real-time session sync.
5️⃣ You Prefer Strongly Typed APIs with Contract-First Design
Use Case: Large-scale enterprise APIs with strict schema validation
Example: A bank’s internal APIs use .proto
contracts to enforce strict structure across all services and languages.
6️⃣ You’re Building a Service Mesh or Internal Platform
Use Case: Secure, observable internal comms in a Kubernetes cluster
Example: With Istio, gRPC traffic between services is encrypted and tracked with tracing headers like Zipkin/Jaeger.
7️⃣ You Need Built-in Support for Deadlines, Retries & Flow Control
Use Case: Payment gateways, fraud detection services
Example: A payment microservice sets deadlines (e.g. 300ms) for downstream calls to avoid cascading timeouts during peak load.
🚫 gRPC Anti-Patterns & When Not to Use It
1️⃣ Replacing REST Everywhere
❌ Anti-pattern: Migrating all REST APIs to gRPC just because it's "faster"
💡 Why avoid: gRPC is optimized for internal, low-latency services — not public APIs. Browsers don't support gRPC natively (without gRPC-Web), making REST a better choice for external consumers.
2️⃣ Using gRPC for CRUD-heavy APIs
❌ Anti-pattern: Rewriting simple CRUD endpoints in gRPC
💡 Why avoid: REST fits better for resource-oriented operations. gRPC adds unnecessary complexity for basic GET/POST/PUT/DELETE logic.
3️⃣ Ignoring Protocol Compatibility
❌ Anti-pattern: Changing .proto
definitions without versioning
💡 Why avoid: gRPC doesn't handle breaking changes well. Clients can break without backward compatibility plans.
4️⃣ Too Many Microservices with Tight Coupling
❌ Anti-pattern: Overusing gRPC to connect microservices that constantly call each other
💡 Why avoid: High coupling over gRPC leads to latency chains and fragile systems. Consider async or event-driven alternatives.
5️⃣ Exposing gRPC APIs Directly to Web/JS Clients
❌ Anti-pattern: Serving gRPC to browsers without gRPC-Web
💡 Why avoid: Browsers can’t consume native gRPC due to HTTP/2 & binary encoding. gRPC-Web or a REST gateway is needed.
6️⃣ Skipping Timeouts and Deadlines
❌ Anti-pattern: Not configuring .withDeadline()
on gRPC calls
💡 Why avoid: This can lead to stuck requests, resource leaks, or cascading failures under load.
7️⃣ Forgetting Monitoring/Tracing
❌ Anti-pattern: No observability on gRPC streams or RPC failures
💡 Why avoid: Debugging gRPC issues without metrics, logs, or traces is painful. Use tools like OpenTelemetry, Zipkin, or Prometheus.
8️⃣ Using gRPC for Long-Lived Connections (e.g. polling-like use cases)
❌ Anti-pattern: Replacing WebSocket-like needs with client-side polling over gRPC
💡 Why avoid: This misuses gRPC’s strengths. Consider proper pub-sub or push mechanisms.
9️⃣ Ignoring Backward Compatibility in Streaming
❌ Anti-pattern: Changing message structure in streaming APIs without schema evolution
💡 Why avoid: Streaming clients may fail midway. Always evolve messages safely.
🔟 Using gRPC in Teams Not Ready for It
❌ Anti-pattern: Adopting gRPC without team familiarity with Protobuf, tooling, or streaming
💡 Why avoid: It increases ramp-up time and dev friction. REST may be better until the team is comfortable.
🛠️ Quick Setup: Your First gRPC Project
with Spring Boot (Maven Edition)
1️⃣ Create a New Spring Boot Project
Use Spring Initializr:
-
Project: grpc-hello-springboot
-
Language: Java 11
- grpc-hello-springboot/ ├── pom.xml ├── src/ │ └── main/ │ ├── java/com/example/grpc/ │ │ ├── GrpcApplication.java │ │ ├── GreeterService.java │ │ ├── GreeterClient.java │ │ └── GreeterController.java │ └── proto/greeter.proto └── src/main/resources/ └── application.properties
grpc-hello-springboot
project:📁 GrpcApplication.java
Responsibility:
-
Entry point for the Spring Boot application (
main()
method). -
Triggers component scanning and starts the embedded Tomcat + gRPC server.
📁 GreeterService.java
Responsibility:
-
Implements the
GreeterGrpc.GreeterImplBase
class generated fromgreeter.proto
. -
Handles gRPC requests on the server (
sayHello()
method). -
Annotated with
@GrpcService
to register it as a gRPC service.
📁 GreeterClient.java
Responsibility:
-
Builds and manages the gRPC client connection to the gRPC server (localhost:9090).
-
Provides a method
sayHello(String name)
that sends a gRPC request to the server.
📁 GreeterController.java
Responsibility:
-
Exposes a REST endpoint at
/api/greet?name=...
. -
Calls the gRPC client internally to forward the request and return the gRPC server's response.
📁 greeter.proto
Role: Protocol buffer contract
Responsibility:
-
Defines the gRPC service interface (
Greeter
) and message types (HelloRequest
,HelloResponse
). -
Used to generate Java classes for both server and client communication.
📁 application.properties
Responsibility:
-
Configures ports:
-
grpc.server.port=9090
→ gRPC server -
server.port=8080
→ REST API
-
-
Can include other Spring or gRPC settings as needed.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.example.grpc";
option java_outer_classname = "GreeterProto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
syntax = "proto3"; option java_multiple_files = true; option java_package = "com.example.grpc"; option java_outer_classname = "GreeterProto"; service Greeter { rpc SayHello (HelloRequest) returns (HelloResponse); } message HelloRequest { string name = 1; } message HelloResponse { string message = 1;
@GrpcService public class GreeterService extends GreeterGrpc.GreeterImplBase { @Override public void sayHello(HelloRequest req, StreamObserver<HelloResponse> responseObserver) { String message = "Hello, " + req.getName(); HelloResponse response = HelloResponse.newBuilder() .setMessage(message) .build(); responseObserver.onNext(response); responseObserver.onCompleted(); } }
@Service public class GreeterClient { private final GreeterGrpc.GreeterBlockingStub stub; public GreeterClient() { ManagedChannel channel = ManagedChannelBuilder .forAddress("localhost", 9090) .usePlaintext() .build(); stub = GreeterGrpc.newBlockingStub(channel); } public String sayHello(String name) { HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloResponse response = stub.sayHello(request); return response.getMessage(); } }
6️⃣ Summary:
GET /api/greet?name=Viral
hits the REST controller.-
Controller calls
GreeterClient.sayHello(name)
-
GreeterClient
makes a gRPC request toGreeterService
via the blocking stub. -
The server returns a gRPC response (
HelloResponse
) which is transformed into a REST response.
✅Code Repository Link
🧭 REST → gRPC Call Flow Diagram
- ┌──────────────────────┐ │ REST Client (e.g. │ │ Postman, browser) │ └──────────┬───────────┘ │ ▼ ┌─────────────────────┐ │ Spring Boot │ │ REST Controller │ │ `GreeterController │ └──────────┬──────────┘ │ Calls ▼ ┌──────────────────────┐ │ gRPC Client Stub │ │ `GreeterClient` │ │ Uses Blocking Stub │ └──────────┬───────────┘ │ ▼ ┌─────────────────────┐ │ gRPC Server │ │ `GreeterService` │ │ extends GreeterImpl │ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ Business Logic │ │ Create gRPC Response │ └──────────┬──────────┘ │ ▼ Response sent backas RES
🚀 What’s Next?
In our next post, we’ll explore:
-
Build these RPC types with real examples
-
Implement them using Spring Boot
-
Understand where and when to use each pattern
👉 Stay tuned for: Advanced gRPC in Spring Boot — Streaming and Beyond!