Build the mental model
REST and gRPC solve the same core problem — letting one program call functionality on another over a network — but optimize for different priorities. REST models everything as resources (a lesson, a user) addressed by URLs, manipulated via standard HTTP verbs (GET, POST, PUT, DELETE), typically exchanging human-readable JSON. That readability and its reliance on plain HTTP make it easy to debug with a browser or curl, easy for any client language to consume, and a natural fit for public APIs where you don't control the caller. gRPC instead defines a strict contract upfront in a .proto file — exact method names, request/response shapes, and types — then generates client and server code in whatever languages you need. It runs over HTTP/2 and serializes messages as compact binary protobuf rather than text JSON, which is significantly faster to parse and smaller over the wire, and it supports native bidirectional streaming. The cost is that payloads aren't human-readable without tooling, and both ends need the shared .proto contract. That trade-off — readability and looseness versus speed and strictness — is exactly why REST dominates public APIs and gRPC dominates internal service-to-service calls where you control both ends and performance compounds across many calls.
Connect it to a real scenario
Thuta Learning exposes two different APIs. Its public REST API lets third-party developers, mobile apps, and browser extensions fetch tutorial content and student progress over plain HTTPS with JSON — anyone can read the docs and start integrating with curl in minutes, which is exactly what an open ecosystem needs. Internally, though, when the lesson-service needs to ask the progress-service and the recommendation-service for data dozens of times per page load, the team uses gRPC between those services — the strict protobuf contract catches mismatched fields at compile time instead of in production, and the binary protocol shaves meaningful latency off every one of those internal calls, which matters when they happen thousands of times per second across the platform.
Try the working example
PUBLIC-FACING
Browser / Mobile App / 3rd-party Dev
|
| REST over HTTPS, JSON
| GET /api/lessons/42
v
+--------------------+
| Tutorial Platform | <-- readable, debuggable with curl,
| Public API | any language can call it, loose
+--------------------+ coupling to caller = good for public
|
| INTERNAL, same team controls both ends
v
+----------------+ gRPC/protobuf +-------------------+
| lesson-service | <-------------> | progress-service |
+----------------+ binary, HTTP/2 +-------------------+
^ strict typed contract, fast,
| streaming supported = good for
| high-volume internal calls
+---------------------+
| recommendation-svc |
+---------------------+The diagram shows REST facing outward toward clients the platform doesn't control, prioritizing readability and loose coupling, while gRPC connects internal services the platform fully controls, prioritizing speed and strict contracts.5-minute try-it
Design the .proto-style contract (method name, request fields, response fields) for a gRPC call between Thuta Learning's lesson-service and progress-service that fetches a student's completion percentage for a course. Then write the equivalent REST endpoint (URL, verb, JSON shape) and compare.
One important caution
Using gRPC for a public API consumed by third-party developers you don't control — most external developers can't easily generate protobuf clients or inspect binary payloads, making integration painful compared to a well-documented REST/JSON API.
Using REST with JSON for extremely high-frequency internal service calls and then being surprised by latency and CPU cost — JSON parsing and larger payload sizes add up fast at the volume internal microservice calls typically run at, which is exactly the case gRPC was built for.
gRPC — Introduction — System Design