If you need both a great public developer experience and high-performance internal communication, the architecture that most teams end up happiest with is:
- Public API: REST (or REST + OpenAPI)
- Internal service-to-service: gRPC
- Spring implementation: Spring MVC for most APIs, WebFlux only where its strengths actually matter
Here's how I'd think about each option.
| Option | External DX | Performance | Streaming | Ecosystem | Complexity |
|---|
| Spring MVC (REST) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Limited (SSE) | Excellent | Low |
| Spring WebFlux (REST) | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Excellent | Very good | Medium |
| gRPC | ⭐⭐ | ⭐⭐⭐⭐⭐ | Excellent | Excellent internally | High |
Spring MVC
This is still the default choice for most public APIs.
Advantages:
- Familiar to every developer
- Works naturally with browsers, curl, Postman, SDK generators
- JSON is easy to inspect
- Excellent OpenAPI support
- Huge ecosystem
- Easier debugging
Performance is often much better than people expect. For typical CRUD APIs, database latency dominates request time, not the HTTP framework.
Good fit:
- SaaS APIs
- Mobile backends
- Partner integrations
- CRUD
- Authentication-heavy APIs
Spring WebFlux
WebFlux isn't automatically faster.
Its biggest advantage is handling many concurrent I/O-bound requests using fewer threads.
Great for:
- API gateways
- Proxy services
- Long-lived connections
- Streaming
- WebSockets
- Reactive databases
- High concurrency
Not ideal if:
- Most work is CPU-bound
- You're using blocking JDBC
- Your team isn't comfortable with reactive programming
Many teams adopt WebFlux expecting higher throughput and instead add unnecessary complexity.
gRPC
gRPC is excellent internally.
Advantages:
- HTTP/2
- Binary Protobuf
- Extremely fast serialization
- Bidirectional streaming
- Strong contracts
- Code generation
- Backward compatibility
Internal services benefit from:
- Lower latency
- Smaller payloads
- Better streaming
- Strong typing
External developers often dislike it because:
- Browsers don't speak native gRPC
- Harder to test with curl
- Binary payloads
- Requires generated clients
- Less discoverable than REST
A hybrid architecture
This is increasingly common.
Clients
│
REST / JSON
│
API Service (Spring MVC)
│
gRPC
│
Internal Services
External:
HTTPS
JSON
OpenAPI
OAuth
Internal:
gRPC
Protobuf
HTTP/2
Streaming
This provides an excellent developer experience while keeping internal communication efficient.
Performance reality
Suppose a request takes:
Network 10 ms
Database 40 ms
Business logic 5 ms
Serialization 1 ms
Switching REST → gRPC might save only a fraction of the total latency because the database dominates.
If your workload is:
- ML inference
- Service mesh
- Microservice fan-out
- Thousands of internal RPCs
then gRPC's gains become much more meaningful.
If you expect streaming
gRPC is significantly better than REST.
Examples:
- Live telemetry
- Chat
- Event streams
- AI token streaming between services
- IoT
REST can use:
- Server-Sent Events (SSE)
- WebSockets
But gRPC's streaming model is more comprehensive.
API evolution
REST:
- Version via URLs or headers
- JSON fields are generally forgiving
- Excellent documentation with OpenAPI
gRPC:
- Evolve Protobuf schemas carefully
- Never reuse field numbers
- Very stable once good practices are followed
Both can be versioned successfully.
Recommendation
For a new platform with both external and internal consumers:
- Public API: Spring MVC + REST + JSON + OpenAPI.
- Internal communication: gRPC + Protobuf over HTTP/2 for service-to-service calls where low latency, streaming, or strong contracts matter.
- Choose WebFlux selectively: adopt it for API gateways, streaming endpoints, or highly concurrent I/O-bound services rather than as a blanket replacement for Spring MVC.
That combination keeps your public API easy to consume while allowing internal services to optimize for performance and efficient communication without exposing that complexity to external developers.