GraphQL vs REST — The Honest Decision Framework
Most teams pick one and apply it everywhere. REST everywhere because that is what they know. GraphQL everywhere because someone read a blog post in 2021 and got excited. Both approaches cause pain — just different pain.
GraphQL was built to solve real problems that REST genuinely has. REST has real advantages that GraphQL genuinely cannot match. The mistake is not choosing the wrong one. The mistake is treating the choice as universal when it is not.
This post gives you a clear framework for choosing between them. No hedging. No ‘it depends’. Just the actual decision criteria — and what each approach costs you when you use it where it does not belong.
🔗 Foundation posts
REST API Design Principles covers the fundamentals of REST — how resources, HTTP verbs and status codes work. Read that first if REST is still fuzzy.
OData Protocol in SAP is directly relevant if you work in the SAP world — OData is REST-based and the concepts here apply directly.
The core difference — one idea each
REST was introduced by Roy Fielding in his 2000 doctoral dissertation. The central idea: model everything as a resource and use standard HTTP verbs to interact with it. A user is a resource. An order is a resource. You get users with GET /users/1. You create orders with POST /orders. Each resource has its own URL, and HTTP handles the rest.
GraphQL was built at Facebook in 2012 and open-sourced in 2015. The problem they were solving was mobile performance — specifically, fetching exactly the data a mobile app needed without the overhead of multiple REST calls. The central idea: expose one endpoint and let the client specify exactly what data it wants in a query.
That is the whole thing. REST: server decides what each endpoint returns. GraphQL: client decides what it gets. Everything else — the tooling differences, the caching trade-offs, the N+1 problem — flows from that one distinction.
The two problems GraphQL was built to solve
REST has two well-known failure modes when clients have varied or complex data needs. GraphQL was designed specifically to fix them.
Over-fetching
Your mobile app needs a user’s name and profile photo. The REST endpoint GET /users/1 returns a full user object — name, email, address, phone number, account settings, preferences. The app uses two fields and discards the rest.
On desktop with a fast connection, this is a minor inefficiency. On a 3G mobile connection in 2012 at Facebook scale — hundreds of millions of users — it was a real problem. Bandwidth costs money. Parsing unused data costs battery.
Under-fetching and the N+1 REST problem
The opposite problem. You need a user’s name plus their last five posts. One REST call gets you the user. Another call gets you the posts. Then you need the author of each post comment — five more calls. One screen, seven HTTP requests.
GraphQL solves this with a single query: ask for the user, their posts, and each post’s comments in one request. The server resolves it all and returns exactly what was asked for.
⚠️ GraphQL has its own version of the N+1 problem — on the server
Ironic but true. If you ask GraphQL for 20 users and each user’s posts, a naive GraphQL resolver makes 1 query for users, then 20 separate queries for posts — one per user. This is the N+1 problem, now server-side.
The solution is the DataLoader pattern — originally built by Facebook. DataLoader batches those 20 post queries into one, reducing them to 2 database calls total. Every serious GraphQL server implementation includes it, but you have to use it deliberately. If you are building GraphQL without DataLoader, you are building a performance problem into your API layer.
Where REST wins — and GraphQL makes things harder
GraphQL is not a universal upgrade. There are scenarios where REST is the right choice and GraphQL adds complexity without benefit.
| Scenario | Why REST wins |
|---|---|
| Public APIs | REST’s URL-per-resource model works perfectly with HTTP caching — CDNs, browser caches, reverse proxies. GET /products/123 is cacheable by any HTTP layer. A GraphQL POST to /graphql with a query body is not, without additional tooling. |
| Service-to-service in microservices | Internal services have narrow, well-defined contracts. A REST endpoint is simpler, cacheable and easier to test than a GraphQL layer for this pattern. |
| File uploads | REST handles multipart/form-data naturally over HTTP. GraphQL file upload is possible but non-standard — it requires middleware and workarounds. |
| Simple CRUD operations | If your API is straightforward create, read, update, delete — REST is faster to build, easier to understand and has more mature tooling. |
| Teams new to API development | GraphQL has a steeper learning curve — schemas, resolvers, query language, DataLoader. REST lets a junior team ship and iterate. |
📌 Key Takeaway
REST’s caching advantage is often underestimated. The entire HTTP caching infrastructure — CDNs, Varnish, browser caches — is built around cacheable URLs. GraphQL throws that away by default. For public APIs with high read traffic, this is a meaningful cost.
Where GraphQL wins — and REST gets painful
Three scenarios exist where GraphQL pays back its setup cost clearly.
Multiple client types with different data needs
Your API serves a web app, an iOS app, an Android app, and a third-party integration. Each client needs different fields from the same underlying data. With REST, you have two options: return everything and let clients filter (over-fetch), or build client-specific endpoints (endpoint sprawl). Neither is good.
GraphQL lets each client request exactly what it needs from a single API. The web app gets the full user profile. The mobile app gets name and avatar only. The third-party integration gets account IDs. One API, three different query shapes.
The Backend for Frontend (BFF) pattern
A BFF is an API layer that sits between your services and your clients, shaped to what each client needs. GraphQL is the natural choice here — it aggregates data from multiple upstream services into one query, letting the frontend fetch a full page’s data in a single round trip instead of orchestrating five REST calls.
This is exactly what Facebook built GraphQL to do. It remains one of GraphQL’s strongest use cases.
Rapid frontend iteration
REST APIs often require a backend change every time a frontend needs a new data shape. GraphQL inverts this — the schema defines what is available, and the frontend queries whatever it needs from that schema without touching the backend. Frontend teams move faster. Backend teams are not blocked by UI changes.
✅ Best Practice
GraphQL’s schema is a contract. Define it carefully and version it thoughtfully — adding fields is non-breaking, removing them is. The schema is also self-documenting via introspection, which tools like GraphiQL and Apollo Studio use to generate API explorers automatically. This is a real operational advantage over REST, where documentation is always a separate effort.
Using both — the pattern that actually works in production
The most mature systems do not choose. They use REST and GraphQL for what each does well.
The pattern that appears consistently in production at scale: REST for service-to-service communication and public APIs where caching matters. GraphQL as the client-facing layer — the BFF — that aggregates those services and serves different client types efficiently.
GitHub’s API is a real-world example. GitHub maintains both a REST API (v3, widely used, heavily cached) and a GraphQL API (v4, for clients that need flexible data shapes). They are not competing — they serve different consumers.
📝 Note — MCP as the third option for AI tooling
Model Context Protocol (MCP), launched by Anthropic in November 2024 and donated to the Linux Foundation in December 2025, is emerging as a third API style for one specific context: AI agents that need to discover and call tools dynamically.
MCP is not a replacement for REST or GraphQL for application APIs — it is purpose-built for the AI agent use case. If you are building integrations for LLM-based systems, read the MCP post. If you are building a regular application API, REST and GraphQL are still your options.
The decision framework — when to reach for which
Use this table. No hedging.
| Scenario | Choose | Reason |
|---|---|---|
| Public API for external developers | REST | HTTP caching, simplicity, broad tooling, familiar to all consumers |
| Service-to-service in microservices | REST | Narrow contract, cacheable, easy to test and monitor |
| File uploads or binary data | REST | Multipart/form-data over HTTP — GraphQL workarounds add friction |
| Simple CRUD with uniform data model | REST | Lower complexity, faster to build, easier to debug |
| Multiple client types with different data needs | GraphQL | Each client queries exactly what it needs from one API |
| BFF layer aggregating services for a frontend | GraphQL | Single round trip, aggregated data, shaped per client |
| Rapid frontend iteration without backend changes | GraphQL | Frontend queries from schema without backend involvement |
| Real-time data with subscriptions | GraphQL | GraphQL subscriptions over WebSocket are native and well-supported |
| High read traffic on cacheable resources | REST | CDN and HTTP cache layer works out of the box — GraphQL needs extra infrastructure |
| Team new to API development | REST | Faster to learn, more tooling, simpler mental model to start |
At a glance — GraphQL vs REST
| Concept | One-line summary |
|---|---|
| REST | Architectural style introduced in 2000 — resources identified by URLs, interacted with via HTTP verbs |
| GraphQL | Query language introduced by Facebook in 2012 — one endpoint, client specifies exactly what data it needs |
| Over-fetching | REST returns more data than the client needs — GraphQL eliminates this by letting clients define the response shape |
| Under-fetching | REST requires multiple requests to assemble a full page — GraphQL resolves this with a single query |
| N+1 problem (GraphQL) | Nested resolvers can trigger N database queries for N items — solved with the DataLoader batching pattern |
| HTTP caching | REST aligns naturally with CDN and browser caching — GraphQL does not by default |
| BFF pattern | Backend for Frontend — GraphQL as the aggregation layer between services and clients |
| Schema (GraphQL) | Strongly typed contract defining available data — self-documenting, introspectable |
| When to use REST | Public APIs, service-to-service, file uploads, simple CRUD, high-cacheability requirements |
| When to use GraphQL | Multiple client types, BFF layer, rapid frontend iteration, real-time subscriptions |
| Using both | The production pattern — REST for services and public APIs, GraphQL for the client-facing layer |
What to take away
The REST vs GraphQL debate has been running for a decade and it is still generating heat because people frame it as a permanent choice. It is not. It is a per-use-case choice — and most systems with enough complexity end up using both.
The real cost of getting this wrong is not a failed project. It is a year of working around the wrong tool. REST applied to a multi-client product with complex data needs produces endpoint sprawl and over-fetching. GraphQL applied to a simple CRUD API or a service mesh produces unnecessary complexity, a caching headache, and a DataLoader you now have to maintain.
Match the tool to the problem. REST for the parts of your system that are stable, cacheable and resource-oriented. GraphQL for the parts that serve multiple clients with different needs. Once you see the two patterns side by side in a real system, the choice becomes obvious — and you stop asking which one wins.
🔗 Related posts on this site
REST API Design Principles — the fundamentals of REST: resources, verbs, status codes and what makes a REST API well-designed.
OData Protocol in SAP — OData is REST with a specification on top. If you work with SAP APIs, this is where the GraphQL vs REST decision becomes concrete.
API Security Essentials — authentication, authorisation and the OWASP API Top 10 apply equally to REST and GraphQL — with some GraphQL-specific considerations worth knowing.
MCP — Model Context Protocol Explained — the third API style emerging for AI agent tooling in 2025-2026, and when it applies instead of REST or GraphQL.
Published on rakeshnarayan.com — Articles
URL: https://rakeshnarayan.com/articles/graphql-vs-rest-the-honest-decision-framework/



Did you enjoy this article?
Let me know — it takes one click.
0 Comments
Leave a Comment
Your comment has been submitted and will appear after review.