The short answer
Quick answer: These are three ways for programs to talk to each other over a network. REST models your data as resources at URLs and uses standard HTTP methods on them. It is simple, cacheable and understood everywhere, which makes it the default for public APIs. GraphQL exposes a single endpoint and a typed schema, and lets the client request exactly the fields it needs in one query. It suits applications with complex, varied screens. gRPC has clients call functions on a server, sending compact binary messages over HTTP/2. It is fast and strictly typed, which suits communication between internal services. Many systems use all three in different places.
REST
REST (Representational State Transfer) is an architectural style defined by Roy Fielding in 2000. In practice it means: nouns in URLs, HTTP verbs for actions, and status codes for outcomes. See the overview on Wikipedia.
GET /users/42
{ "id": 42, "name": "Ada Lovelace", "email": "[email protected]", "createdAt": "2026-01-04T10:00:00Z" }
| Method | Meaning | Example |
|---|---|---|
| GET | Read | GET /users/42 |
| POST | Create | POST /users |
| PUT / PATCH | Replace / update | PATCH /users/42 |
| DELETE | Remove | DELETE /users/42 |
Each request is stateless: it carries everything the server needs.
Strengths
- Simple and universal. Any language, any tool; you can test it with a browser or curl.
- HTTP caching works.
GETresponses can be cached by browsers and CDNs with standard headers. - Standard semantics. Status codes, methods and headers mean the same thing everywhere.
- Mature tooling, including OpenAPI for describing and documenting APIs.
Weaknesses
- Over-fetching. The endpoint returns the whole resource even if you want one field.
- Under-fetching. A screen showing a user, their posts and each post's comments may need several round trips.
- Endpoint sprawl. Teams add special endpoints for each screen's needs.
- No built-in schema. A contract exists only if you write and maintain one.
- Versioning becomes a concern as the API evolves.
GraphQL
GraphQL was created at Facebook and released publicly in 2015, originally to serve mobile apps on slow networks. The official introduction describes it as a query language for your API.
There is one endpoint. The client sends a query describing the shape of data it wants:
query {
user(id: 42) {
name
posts(first: 3) {
title
comments { text }
}
}
}
The response has exactly that shape, and nothing more:
{
"data": {
"user": {
"name": "Ada Lovelace",
"posts": [
{ "title": "On the Analytical Engine", "comments": [{ "text": "Remarkable." }] }
]
}
}
}
The server defines a strongly typed schema. Queries read, mutations write, and subscriptions push updates. Each field is backed by a function called a resolver.
Strengths
- No over- or under-fetching. One request, precisely the data needed.
- A typed, self-documenting schema. Tools can explore it, validate queries and generate client code.
- Front-end teams move independently. A new screen needing different fields does not require a new endpoint.
- Evolves without versions. Add fields freely; mark old ones as deprecated.
Weaknesses
- Caching is harder. Queries are usually sent as
POSTto a single URL, so ordinary HTTP caching does not apply without extra techniques. - The N+1 problem. Resolving each field separately can produce a flood of database queries unless you batch them with a pattern such as DataLoader. See the N+1 query problem.
- Expensive queries. A client can ask for deeply nested data. Servers need depth limits, complexity limits or an allow-list of permitted queries.
- Server complexity. There is more machinery to build, secure and monitor.
- Errors are returned inside a
200response, which changes how monitoring works. - Awkward for file uploads and simple cases.
gRPC
gRPC is an open-source framework from Google, released in 2015. See the overview on Wikipedia. It follows the remote procedure call model: the client calls a method as if it were a local function.
You define the service and its messages in a .proto file using Protocol Buffers:
syntax = "proto3";
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc WatchUsers (WatchRequest) returns (stream User);
}
message GetUserRequest { int64 id = 1; }
message User {
int64 id = 1;
string name = 2;
string email = 3;
}
From that file, a compiler generates client and server code in many languages. Messages are encoded in a compact binary format and sent over HTTP/2.
Strengths
- Fast and small. Binary encoding is more compact and quicker to parse than JSON, and HTTP/2 carries many calls over one connection. See why HTTP/2 and HTTP/3 exist.
- Strict contracts. The
.protofile is the single source of truth, and generated code catches mismatches at compile time. - Streaming is built in: from server to client, client to server, or both at once.
- Works across languages, which suits organisations with services in several.
- Built-in deadlines, cancellation and metadata.
Weaknesses
- Browsers cannot call it directly. They need gRPC-Web and a proxy, or a similar bridge.
- Not human-readable. You need tools to inspect or debug messages.
- Tighter coupling. Client and server share generated code, and schema changes must follow compatibility rules.
- Needs infrastructure that understands HTTP/2, including load balancers that balance per request and not per connection.
Side by side
| REST | GraphQL | gRPC | |
|---|---|---|---|
| Model | Resources | A graph of typed fields | Procedures |
| Endpoints | Many | One | One per method |
| Data format | Usually JSON | JSON | Protocol Buffers (binary) |
| Transport | HTTP/1.1 or newer | HTTP | HTTP/2 |
| Schema | Optional (OpenAPI) | Required | Required (.proto) |
| Client chooses the fields | No | Yes | No |
| HTTP caching | Straightforward | Difficult | Not applicable |
| Streaming | Limited | Subscriptions | Native, in both directions |
| Browser support | Native | Native | Needs a bridge |
| Human-readable | Yes | Yes | No |
| Typical use | Public APIs, CRUD | Apps with complex, varied views | Service-to-service calls |
How to choose
- A public API for other developers: REST. It has the lowest barrier to entry.
- Web and mobile apps with rich, nested screens, or several client types needing different data: GraphQL.
- Internal microservices where performance and strict contracts matter: gRPC. See monolith vs microservices.
- Simple CRUD: REST.
- Real-time, two-way streams between services: gRPC streaming. For browsers, see how WebSockets work.
- A small team with one client: REST, or the simplest thing your framework offers.
A common large-system layout uses all three: gRPC between internal services, a GraphQL or REST layer facing the web and mobile apps (sometimes called a backend for frontend), and REST for the public API.
Other options exist too. tRPC gives end-to-end type safety when the client and server are both TypeScript. Webhooks let a server call you when something happens. Server-Sent Events push one-way updates.
What matters whichever you pick
- Authentication and authorisation. See JWT vs sessions.
- Rate limiting. See how rate limiters work.
- Pagination for lists.
- Consistent, informative errors.
- Idempotency for operations that may be retried. See idempotency.
- Backwards compatibility. Add; do not remove or rename.
- Documentation.
A badly designed API is painful in any style, and a well-designed one is pleasant in any style.
Frequently asked questions
Is GraphQL better than REST?
Not in general. GraphQL solves over- and under-fetching for complex clients, at the cost of harder caching and more server complexity. REST is simpler and caches well.
Is gRPC faster than REST?
Usually, because of binary encoding and HTTP/2. For many applications the difference is small next to database and network time.
Can browsers use gRPC?
Not directly. Browser applications use gRPC-Web or a similar protocol, through a proxy.
Can I use more than one?
Yes, and many organisations do: gRPC internally, with REST or GraphQL at the edge.
Conclusion
REST, GraphQL and gRPC answer different needs. REST is the common language of the web, GraphQL gives clients control over the data they receive, and gRPC makes service-to-service calls fast and strictly typed. Choose by who is calling your API and what they need from it, and remember that careful design matters more than the style.
Related articles
- What Is the N+1 Query Problem and How to Fix It
- Why HTTP/2 and HTTP/3 Exist: The Problems They Solve
- How WebSockets Enable Real-Time Apps Like Chat and Live Scores
- Monolith vs Microservices: Why Companies Switch (Both Ways)
