Direct answer
For an internal microservices platform, prefer gRPC for service-to-service calls: its binary encoding and HTTP/2 transport give lower latency and smaller payloads at high call volumes, and its contract-first interface keeps many services in sync automatically. For anything a browser calls directly, prefer REST over plain HTTP and JSON, because a browser cannot open a native gRPC connection at all.
Framework
REST is an architectural style over HTTP that uses JSON bodies, standard HTTP methods, and standard status codes. gRPC is a contract-first remote procedure call framework that runs over HTTP/2 and encodes messages with Protocol Buffers (protobuf), a compact binary serialization format defined by a .proto schema file that generates client and server code in multiple languages.
| Dimension | REST (HTTP + JSON) | gRPC (HTTP/2 + protobuf) |
|---|
| Payload | Text (JSON), larger, human-readable | Binary (protobuf), smaller, not human-readable on the wire |
| Transport | HTTP/1.1 or HTTP/2, typically one request per response | HTTP/2 only, many requests multiplexed over one connection |
| Streaming | Bolted on via WebSockets or Server-Sent Events | Native client, server, and bidirectional streaming |
| Contract | Loose, documented separately (for example an OpenAPI spec) and easy to drift from the code | Strict: a .proto file generates both sides' code, harder to drift silently |
| Browser support | Native (fetch, XMLHttpRequest) | Not native; needs gRPC-Web plus a translating proxy |
| Caching and intermediaries | Works with standard HTTP caches, CDNs, and load balancers out of the box | Binary framing and multiplexing make generic HTTP caching not applicable |
| Best fit | Public APIs, browser clients, wide interoperability | Internal, high-volume, latency-sensitive service-to-service calls |
For the internal platform: gRPC, because service-to-service calls are usually high in volume, latency-sensitive, and made by services the team already controls, so the cost of generating and deploying stubs from a shared .proto file pays off, and the smaller binary payload plus multiplexed streams cut both bandwidth and per-connection overhead compared to many REST connections.
What changes for a browser: a browser's networking stack cannot speak native gRPC, because it cannot control HTTP/2 framing and trailers the way a gRPC client library does. Two ways to still reach the same backend from a browser: put a REST/JSON facade in front of the gRPC service (a translation layer sometimes called a backend for frontend), or use gRPC-Web, a variant browsers can speak that still needs a proxy in front of the gRPC service (commonly Envoy) to translate wire formats, and that does not support the full bidirectional streaming native gRPC does. In practice, most teams pick REST/JSON for anything a browser calls directly and keep gRPC strictly behind that boundary.
A third style, GraphQL, is not really the comparison this question is asking for. It trades either extreme for a single flexible query language over HTTP, and it would be the right answer if the real problem were a client needing to shape its own response across many resources at once, not the internal-platform protocol choice being asked about here.
Worked example
Suppose an internal order service calls an inventory service 50 times per incoming user request, once per line item, to check stock. With REST/JSON, each call opens or reuses an HTTP connection and pays JSON parsing cost per call. With gRPC, all 50 calls can multiplex over a single HTTP/2 connection to the inventory service, and each message is a compact protobuf encoding instead of a JSON object with repeated field-name strings, so the marginal cost per call is lower at that fan-out.
If that same platform later needs to expose an inventory check directly to a web storefront, the storefront calls a REST endpoint instead:
json
GET /v1/inventory/A1
200 OK
{ "sku": "A1", "in_stock": 42 }
The storefront is never handed a .proto file or a gRPC client; it gets ordinary JSON over HTTP.
Trade-offs and pitfalls
- gRPC's stricter schema is also a cost: every field change means regenerating and redeploying stubs across every consuming service, whereas REST/JSON tolerates an unexpected extra field without anyone regenerating anything.
- A common pitfall is exposing gRPC-Web directly to third-party public API consumers to save engineering time. It forces every external integrator to adopt protobuf tooling and a compatible proxy, which is a worse experience than JSON for most public consumers.
- Debugging gRPC's binary frames is not as simple as opening a browser's network tab or running curl the way it is with JSON; teams that skip investing in gRPC-aware tracing early often regret it once they have many services talking to each other.