REST vs gRPC: When to Use Each, Plus Protobuf vs JSON
gRPC inside your system, REST at the edge, a queue when nobody waits. A decision table on payload size, speed, streaming and gRPC-Web browser limits, built from the official docs.

11 min read · Last updated: October 24, 2026
REST vs gRPC, when to use each: use gRPC with Protocol Buffers for internal service-to-service calls where you control both ends and need speed, strict contracts or streaming. Use REST with JSON for public and browser-facing APIs. Use async messaging like Kafka when the caller should not wait for the answer at all.
Came here from Instagram, LinkedIn, X or YouTube? Here is the full source list you came for. Everything below is built from these, nothing else.
The gRPC docs and specs
- gRPC core concepts: the four method types and deadlines (grpc.io)
- gRPC over HTTP/2 wire protocol spec (grpc/grpc on GitHub)
- gRPC-Web protocol spec (grpc/grpc on GitHub)
- gRPC-Web README: supported modes and proxies (grpc/grpc-web)
The Protocol Buffers docs
- Protocol Buffers overview, including "When Is Protobuf Not a Good Fit?" (protobuf.dev)
- Protobuf wire encoding guide (protobuf.dev)
- ProtoJSON, the canonical JSON mapping (protobuf.dev)
The standards
The alternatives
- Connect RPC introduction (connectrpc.com)
- Apache Kafka introduction (kafka.apache.org)
- Introduction to GraphQL (graphql.org)
The benchmark
Here is the decision in one line. gRPC inside your system, REST at the edge, a message queue when nobody needs to wait.
Most teams argue about this as if it were one choice. It is two. The first is the API style: REST (resources over HTTP) or gRPC (remote procedure calls over HTTP/2). The second is the data format: JSON (text) or Protocol Buffers (binary). gRPC uses Protobuf by default and REST usually uses JSON, but you can mix them.
Key takeaways
- The value 150 in a Protobuf field takes 3 bytes on the wire. The same field as JSON,
{"a":150}, takes 9 bytes. - In Auth0's 2017 benchmark between two Java services, Protobuf requests took 78% less time than JSON uncompressed, and were 6 times faster compressed (25ms vs 150ms).
- In browsers with compression on, the same benchmark found Protobuf only 9% smaller and 4% faster.
- gRPC supports 4 call types, including bidirectional streaming. gRPC-Web in the browser supports only 2: unary and server streaming.
- Protobuf's own docs say to consider something else for data that exceeds a few megabytes.
REST vs gRPC vs Protobuf vs JSON: the comparison table
The table compares the two pairings you will actually choose between: REST with JSON and gRPC with Protobuf. Every row comes from the docs and specs in the source list.
| REST + JSON | gRPC + Protobuf | |
|---|---|---|
| Transport | Any HTTP version | HTTP/2 framing |
| Payload | Text, field names repeated in every message | Binary, only field numbers on the wire |
| Example size | {"a":150} = 9 bytes | 08 96 01 = 3 bytes |
| Contract | Optional (OpenAPI if you add it) | Required .proto file, code generated |
| Streaming | Request and response, plus SSE or WebSockets on the side | Unary, server, client and bidirectional streaming built in |
| Browser support | Native, every browser | Needs gRPC-Web, unary and server streaming only |
| Debugging | Readable in curl or DevTools | Needs the .proto to decode a message |
| Errors | HTTP status codes | grpc-status sent in HTTP/2 trailers, even on success |
| Timeouts | You build them | Deadlines are part of the protocol |
| Best for | Public APIs, browsers, partners, webhooks | Internal service-to-service calls, polyglot backends, streaming |
Is gRPC faster than REST?
Usually yes for service-to-service calls, but most of the gain comes from Protobuf being smaller and faster to parse than JSON, plus HTTP/2 running many requests over one connection. In Auth0's 2017 benchmark between two Java services, Protobuf requests took 78% less time than JSON. In browsers with compression on, the gap shrank to 4%.
There are two separate speed wins. Keep them apart.
The format. Protobuf's overview describes it as "like JSON, except it's smaller and faster." JSON repeats every field name as text in every message. Protobuf sends a field number and a compact value, so the parser does less work.
The transport. RFC 9113, the HTTP/2 standard published in June 2022, says HTTP/2 reduces latency "by introducing field compression and allowing multiple concurrent exchanges on the same connection." gRPC is specified on HTTP/2 framing, so every gRPC call gets that. REST can run on HTTP/2 too, which narrows this part of the gap.
Now the honest part. The Auth0 numbers measure Protobuf vs JSON over plain HTTP between Spring Boot apps, not gRPC vs REST end to end. The test sent 500 GET requests carrying 50,000 Person records between two DigitalOcean machines. Real APIs usually send much less. For single-record POST requests, the same benchmark found message sizes "effectively the same" and Protobuf only 4% faster.
If speed is your reason to switch, measure your own payloads first.
Protocol Buffers vs JSON: size and speed
Protocol Buffers is smaller than JSON because it never sends field names, only a field number, a wire type and a compactly encoded value. One integer field set to 150 is 3 bytes in Protobuf and 9 bytes as JSON. The cost is readability: you cannot interpret a Protobuf message without its .proto schema.
Here is the exact example from the Protobuf encoding guide. The schema:
syntax = "proto3";
message Test1 {
int32 a = 1;
}
Set a to 150 and serialize it. The guide shows the bytes:
08 96 01
08 means "field 1, varint." 96 01 is 150 as a varint, where each byte carries 7 bits of value and 1 bit that says "more bytes follow." The name a never appears. Compare JSON:
{"a":150}
That is 9 bytes. Rename the field to accountBalance and the JSON grows. The Protobuf stays at 3 bytes.
JSON has its own fine print. RFC 8259, the JSON standard from December 2017, says integers are only reliably interoperable between -(2^53)+1 and (2^53)-1. That is why ProtoJSON, Protobuf's official JSON mapping, emits 64-bit integers as strings "to ensure no precision loss." If you send large database IDs as JSON numbers, this will bite you.
Protobuf's docs are also clear about where it does not fit. From the "When Is Protobuf Not a Good Fit?" section:
- "For data that exceeds a few megabytes, consider a different solution."
- "Messages are not compressed." You can gzip them like any file.
- "You cannot fully interpret one without access to its corresponding .proto file."
- "Protobuf is not a formal standard of any organization." JSON is an IETF standard.
Can gRPC be used in the browser?
Not directly. Browsers do not expose the HTTP/2 framing gRPC needs, so you use gRPC-Web, a separate protocol. Classic gRPC-Web needs a proxy such as Envoy in front of your gRPC server and supports only unary and server-streaming calls. Client streaming and bidirectional streaming do not work in the browser.
The gRPC-Web spec gives the reason: it has to "decouple from HTTP/2 framing which is not, and will never be, directly exposed by browsers." So it moves the trailers, where gRPC puts its status code, into the response body.
The grpc-web README lists the limits:
- It "currently supports 2 RPC modes": unary and server-side streaming.
- Server streaming works "Only when grpcwebtext mode is used," the base64 text format.
- The binary
grpcwebmode supports unary calls only. - "Client-side and Bi-directional streaming is not currently supported."
- Clients "connect to gRPC services via a special proxy," with Envoy as the default. Nginx, Apache APISIX and a Go proxy also work.
There is a second route. Connect, a set of libraries for Protobuf APIs, supports "gRPC, gRPC-Web, and Connect's own protocol" and serves gRPC-Web "without relying on a translating proxy like Envoy." Its own protocol runs over HTTP/1.1 and HTTP/2 and accepts both JSON and binary Protobuf. If you want one .proto file to serve your backend and your frontend, start there.
If your frontend only needs plain request and response, REST with JSON is still the shortest path. For another RPC-style option in the browser, see my breakdown of Cap'n Web, Cloudflare's RPC library.
When should I use gRPC?
Use gRPC when you own both the client and the server, they talk often, and you want a strict contract, generated clients in several languages, streaming, or lower latency. Skip it for public APIs, third-party integrations and anything a browser calls directly, where REST with JSON is simpler to adopt and debug.
The gRPC strengths that matter day to day:
- The contract is the code. One
.protofile generates typed clients and servers. A renamed field breaks the build, not production. - Streaming is built in. The core concepts page lists four method types: unary, server streaming, client streaming and bidirectional streaming.
- Deadlines are built in. gRPC "allows clients to specify how long they are willing to wait for an RPC to complete." In a chain of five services, that stops one slow call from hanging everything.
- Many calls, one connection. HTTP/2 multiplexing means a chatty service does not open a new connection per request.
The REST strengths gRPC does not replace:
- Anyone can call it. curl, a browser, Postman, a partner's PHP script. No code generation.
- You can read it. A JSON response in DevTools explains itself.
- HTTP status codes. Caches, load balancers and monitoring tools already understand them. New to this? Start with REST APIs explained for beginners.
Kafka messages vs REST calls between services
Use REST or gRPC when the caller needs an answer right now to continue, like checking a price before checkout. Use Kafka, the open-source event streaming platform, when the caller only needs to announce that something happened and other services react later, like "order placed." A slow consumer never blocks the producer.
The Kafka introduction describes producers and consumers as "fully decoupled and agnostic of each other." That is the core difference. A REST call fails if the other service is down. A Kafka event waits in the topic until the consumer comes back.
Two details from the Kafka docs shape most designs:
- "Events are not deleted after consumption." Each topic keeps events for a retention period you configure, so a new service can replay history.
- Events with the same key go to the same partition, and consumers read a partition "in exactly the same order as they were written." Ordering is per partition, not per topic.
Most real systems use both. Checkout calls payments synchronously, then publishes an event that email, analytics and inventory consume on their own time. This trade-off comes up constantly in system design interviews, and the deciding question is always whether the caller has to wait.
GraphQL vs gRPC for microservices
GraphQL and gRPC solve different problems. GraphQL is a query language that lets a client, usually a frontend, ask for exactly the fields it needs in one request. gRPC is for fast, typed calls between backend services. A common pattern uses both: GraphQL at the edge for the UI, gRPC between the services behind it.
The GraphQL docs define it as "a query language for your API, and a server-side runtime for executing queries using a type system you define for your data." Its strength is that a client can "receive just that data in the expected shape with a single request." That matters for a mobile screen that would otherwise call five REST endpoints.
For many services, GraphQL offers federation, "composing services into a unified schema." That is a gateway job. Service-to-service traffic still wants the fixed contract and low overhead of gRPC.
REST vs gRPC: when to use each, by situation
Pick by who calls the API and whether they wait for the result. This is the table I would use.
| Your situation | Pick | Why |
|---|---|---|
| Public API for outside developers | REST + JSON | Anyone can call it, no code generation |
| Browser calls your backend, plain request and response | REST + JSON | Native in every browser, readable in DevTools |
| Browser needs live updates from the server | gRPC-Web, Connect, or REST + SSE | gRPC-Web supports server streaming in text mode |
| Browser needs client or bidirectional streaming | WebSockets | gRPC-Web does not support these modes |
| Internal services in several languages | gRPC + Protobuf | One .proto, generated typed clients |
| High-volume internal calls where latency matters | gRPC + Protobuf | Smaller payloads, HTTP/2 multiplexing, deadlines |
| One service announces an event, many react later | Kafka or another message broker | Producer never waits, events can be replayed |
| A frontend needs data from many services at once | GraphQL at the edge, gRPC behind it | Client picks fields, backend keeps strict contracts |
| Payloads larger than a few megabytes | Stream files or use object storage | Protobuf's docs say to consider a different solution |
| Small team, one backend, one frontend | REST + JSON | The extra tooling does not pay for itself yet |
One warning. Teams often adopt gRPC "because it is faster," then spend a month on proxies, codegen pipelines and decoding binary payloads. Pick gRPC for the contract and the streaming. Treat the speed as a bonus.
FAQ
Is gRPC always faster than REST?
No. gRPC tends to win on large or frequent internal calls because Protobuf is compact and HTTP/2 multiplexes requests. For small payloads the gap shrinks: in Auth0's 2017 benchmark, single-record POST requests were effectively the same size and Protobuf was only 4% faster. Measure your own traffic before switching.
Can I use Protocol Buffers with REST?
Yes. Format and API style are separate choices. You can send binary Protobuf over a normal HTTP endpoint, which is what the Auth0 benchmark did between two Spring Boot apps. Protobuf also has an official JSON mapping, ProtoJSON, so one schema can serve binary and JSON clients.
Should a startup use gRPC from day one?
Usually not. With one backend and one frontend, REST with JSON is faster to build, debug and hand to new developers. Add gRPC when several internal services talk constantly, you need streaming, or you want generated clients across languages.
Pick the one internal call in your system that runs most often and measure it before you rewrite anything, then use the free tools on Art of Code to format and inspect the JSON you send today. If you are rethinking how your internal APIs report errors too, read why your private API doesn't need HTTP status codes.
Written by Adithya Guttha, Founder of Art of Code.
Sign in to like and save posts.
Keep reading



Discussion
Comments (0)
Want to join the conversation?
Sign in to commentNo comments yet. Be the first to comment!