In a 2021 benchmark run on a single local machine, a REST endpoint returning a small JSON object beat its gRPC equivalent on raw latency. Two years later, when a Northeastern University team reran the same test suite across distributed cloud instances at far higher load, that same REST design's throughput for large payloads fell to roughly 1% of what it delivered for small ones. The gRPC and HTTP-with-Protobuf endpoints tested alongside it barely slowed down.
Two Benchmarks, Six Years Apart, Point the Same Direction
The original comparison came from Recep İnanç, a software developer who built matching REST and gRPC endpoints in Spring Boot and load-tested them with JMeter on his own machine, publishing the full project on GitHub. He was upfront that the test measured the two implementations only relative to each other, not absolute real-world performance. Depending on payload size, the result shifted: REST won at the smallest payload, the two were close at a medium size, and gRPC pulled ahead once the payload grew.
In 2023, Ian Gorton, a professor at Northeastern University's Seattle campus, and graduate student Yingyi Tong reused İnanç's exact API implementations and JMeter test plans but moved the test onto Google Compute Engine, running the client on a 4-vCPU instance and the server on a 16-vCPU instance in the same subnet. Their thread groups ramped up to 100 and then 500 simulated clients, each requesting batches of 1, 100, or 1,000 pre-cached large objects, with a final stress run at 100,000 objects to see where each implementation broke down. They also added a third configuration: REST-style JSON endpoints and their protobuf-serialized twin, sent over the same HTTP/1.1 transport gRPC does not use. That extra configuration turned out to matter for figuring out what was actually driving the gap, and it is the detail the original 2021 test never included.
REST's Collapse Is a Payload-Size Problem, Not a Protocol-Overhead One
At 500 concurrent client threads, Gorton and Tong found REST's throughput for large payloads dropping to about 1% of its own small-payload throughput. gRPC and the HTTP-with-Protobuf endpoint degraded far less: gRPC outperformed HTTP-with-Protobuf by roughly 25 to 30% at scale and beat REST by more than 9 times on large payloads. The 99th-percentile response time for REST came out around 11 times gRPC's at the largest tested size. Under a deliberate stress test of 100,000 returned objects, REST's p99 reached about 30 seconds, while gRPC and HTTP-with-Protobuf both stayed near 7 seconds.
That HTTP-with-Protobuf control condition is the useful part of this dataset. It runs over the same HTTP/1.1 transport as REST, but carries the same compact binary payload gRPC does, which in Gorton and Tong's tests ran at roughly a third the size of the equivalent JSON. Because that hybrid tracked gRPC's resilience far more closely than it tracked REST's collapse, the transport layer is not what is driving the difference here; the serialization format is. Neither post frames it this way directly, but it follows from comparing their own three-way results side by side. For a service deciding between REST and gRPC purely on speed grounds, that reframes the real question: it is less "HTTP/1.1 or HTTP/2" and more "text or binary on the wire."
HTTP/2 Framing and Binary Encoding: The Mechanism Behind the Numbers
JSON has to be parsed as text: quotes, braces, and delimiters recounted on every read. Protocol Buffers skip that step, encoding fields into a binary layout the receiving side decodes directly using the same schema. Layered independently on top of that, HTTP/2 lets gRPC multiplex several requests over one connection instead of queuing them, which matters most under concurrent load rather than in a single-request timing.
The shape of an implementation illustrates the same split. A REST route in Express.js accepts a request, serializes a JavaScript object to JSON, and writes it to the response stream:
app.get('/product/:id', async (req, res) => {
const product = await getProduct(req.params.id);
res.json(product); // JSON.stringify under the hood
});A gRPC service instead defines the message shape in a .proto file, and the generated code handles binary encoding without an intermediate text step:
message Product {
string id = 1;
string name = 2;
double price = 3;
}
service Catalog {
rpc GetProduct (ProductRequest) returns (Product);
}Neither snippet is the literal code Gorton, Tong, or İnanç benchmarked; both are minimal sketches of the shape of the two approaches, included to show where the parsing step disappears, not to claim a timed result for Express.js specifically.
The Express.js Gap: What Node's Single-Threaded Runtime Leaves Unmeasured
That caveat matters because none of the numbers above come from Node.js or Express. Both benchmarks ran Java implementations on Spring Boot. A separate 2019 test by developer Sergii Onufriienko did compare REST-over-HTTP/1.1, REST with keep-alive, and gRPC-with-Protobuf on two Node.js microservices running on AWS c5.large instances, with source code published on GitHub. But its results were published only as chart images, with no accompanying numeric table in the post itself, so a precise gRPC-versus-Express multiplier cannot be quoted from the public record the way the JVM figures above can. A reader response to that test also flagged that its client awaited each request in sequence rather than issuing them concurrently, which would understate whatever advantage gRPC's HTTP/2 multiplexing offers on Node specifically.
No public, methodologically transparent benchmark currently pairs Express.js with gRPC at the load and scale Gorton and Tong tested for Java. Node's single-threaded event loop and V8's JSON handling are different enough from the JVM that the payload-size threshold where REST's throughput starts to fall could land in a different place. Until that test exists, the honest summary for a Node or Express team is the mechanism above, not a specific number: binary encoding removes a parsing cost that JSON always pays, and that cost compounds as payload size and request volume grow.
The teams that have already made this switch inside their own stacks tend to describe the same tradeoff in practical terms rather than raw benchmark numbers, weighing the schema and tooling overhead of Protocol Buffers against the throughput ceiling of JSON at scale; our own account of moving internal microservices from REST to gRPC walks through that decision in more operational detail than a load test alone can.





Comments (0)
Please sign in to join the discussion.
No comments yet.
Be the first to share your perspective on this topic.