REST API vs GraphQL: choosing the right approach
A client pings you at 11pm: the mobile app is slow, and the dashboard team wants three new fields on the same screen. You pull up the network tab. Eight REST calls for one page, each returning a fat JSON blob where the app uses maybe a third of the fields. Sound familiar? That was the exact moment, about two years ago, when I started taking GraphQL seriously instead of treating it as a conference-talk curiosity.
But here is the honest part: after migrating one service and regretting it, then leaving another on REST and feeling fine about it, I stopped believing there is a universal winner. The choice between REST API and GraphQL is not about which one is newer. It is about matching the shape of your data and your clients to the shape of the tool.
Key Takeaways
- REST wins when your resources are stable, your caching matters, and your clients are simple or public.
- GraphQL wins when many clients need different slices of the same graph and over-fetching is costing you real bandwidth.
- GraphQL does not remove N+1 problems. It hides them until your resolver layer explodes under load.
- Caching is where REST quietly crushes GraphQL: HTTP cache headers work out of the box, GraphQL needs custom work.
- Security on GraphQL means query depth limits and cost analysis, not just an auth header.
- You can run both. Plenty of teams expose REST for public consumers and GraphQL internally.
The real difference nobody puts in the comparison table
Most comparisons start with "REST uses multiple endpoints, GraphQL uses one." True, and almost useless on its own. The difference that actually bites you in production is who decides the shape of the response.
With REST, the server decides. You ask for /users/42/orders and you get whatever the backend team thought was reasonable. With GraphQL, the client decides. The client writes a query and gets exactly the fields it asked for. That shift sounds small. It rewrites your whole architecture.
Over-fetching and under-fetching, in practice
I once measured a product listing screen on REST: the endpoint returned 41 fields per product, the app rendered seven of them. Multiply that by 20 products per screen and a few hundred thousand daily users, and you are paying for a lot of JSON nobody reads. Switching that screen to a GraphQL query cut the payload to roughly a fifth of its size. Real, measurable, and the kind of number that gets a migration approved.
But the flip side is under-fetching. On REST, a screen needing user + orders + address means three or four round trips. GraphQL collapses that into one request with nested fields. On a flaky mobile connection, fewer round trips matters more than raw bytes.
REST vs GraphQL: a side-by-side you can actually use
| Criterion | REST | GraphQL |
|---|---|---|
| Endpoints | One per resource | Single endpoint, query-driven |
| Caching | Native HTTP caching, CDN-friendly | Needs custom cache layer or persisted queries |
| Over-fetching | Common | Largely solved by client-written queries |
| Versioning | Versioned URLs (/v2) | Schema evolution, field deprecation |
| Error handling | HTTP status codes | 200 with an errors array |
| Learning curve | Low | Steep: schema, resolvers, tooling |
| Best fit | Public APIs, simple CRUD | Multiple clients, complex graphs |
Notice the caching row. That single difference has decided more of my architecture choices than anything else on the list.
GraphQL vs REST performance: the part the benchmarks skip
People assume GraphQL is faster. Sometimes it is. Often it is not, and the reason is boring: resolvers.
In REST, your ORM query is written once, in one place, by someone who thought about it. In GraphQL, each field can trigger its own resolver, and a naive implementation fires a separate database query per item. That is the classic N+1 problem, and GraphQL does not solve it. It just makes it easier to write without noticing. I watched a query that returned in 80ms on my laptop take 1.4 seconds in staging because a nested field hit the database 200 times.
When to use REST vs GraphQL
My rule of thumb, refined by too many mistakes:
- Choose REST if your data is resource-shaped, your clients are predictable, and CDN caching saves you money.
- Choose GraphQL if three or more clients (web, iOS, Android, partner integrations) each need a different view of the same data.
- Stay on REST if your team is small and has no bandwidth to run a GraphQL gateway, monitoring, and query cost analysis.
- Consider GraphQL if rapid frontend iteration keeps forcing backend changes just to add one field.
The second and fourth points are where GraphQL genuinely earns its keep. Not performance. Velocity.
The operational costs nobody mentions
Here is where I got burned. Migrating a service to GraphQL is not a weekend project. You inherit a schema to maintain, a gateway to run, and an observability problem: a single GraphQL request can hit ten downstream services, and your old per-endpoint dashboards become useless. Rate limiting also gets harder, because you cannot limit by URL anymore. You limit by query complexity, which means you have to estimate query cost before running it.
Security deserves its own paragraph. With REST, a malicious client can hammer one endpoint. With GraphQL, a single deeply nested query can pull your whole database into memory. Introspection, left open, hands attackers a full map of your schema. You need depth limits, cost analysis, and disabled introspection in production. Miss any of those and you have built a denial-of-service button and labeled it "flexible API."
What about gRPC?
Worth a mention since it comes up in the same conversations. gRPC is fast, strongly typed, and great for service-to-service communication inside your infrastructure. It is a poor fit for browser clients and public APIs where REST and GraphQL shine. In one backend I worked on, we used gRPC between internal services and exposed REST to the outside world. Nobody missed anything.
The honest answer: it is a trade, not a verdict
After building on both, my position is this: pick REST as your default, and reach for GraphQL when the pain of over-fetching and multi-client divergence becomes concrete and expensive. Do not adopt GraphQL because it is fashionable, and do not defend REST out of habit. The worst outcome is not choosing the "wrong" one. It is running GraphQL without the operational maturity to support it, or forcing REST to serve a data graph it was never shaped for.
The next time someone asks you to pick a side, ask them one question first: who actually needs to decide the shape of the response, the server or the client? Your answer is already in that sentence.