GraphQL vs REST: What I Learned Building Both in Production
The problem GraphQL actually solves
REST's failure mode is structural: an endpoint returns a fixed shape, and every client either over-fetches (gets fields it doesn't need) or the API grows a combinatorial explosion of query params and partial-response flags trying to let clients ask for less. A mobile app showing a product thumbnail and a desktop app showing full specs end up hitting the same bloated /products/:id response, or you maintain two endpoints. GraphQL's single biggest real win is letting each client ask for exactly the shape it needs from one schema, with no endpoint proliferation.
What GraphQL costs you that REST doesn't
- N+1 by default. A naive resolver for
Order { items { product { name } } }will issue one query per order, then one per item, then one per product — unless you implement batching (DataLoader) from day one. This isn't optional; it's the first thing that breaks under real traffic. - Query complexity as an attack surface. A client can send a deeply nested query that fans out into thousands of database calls. You need query depth limiting and cost analysis in a way REST — where the server defines every possible query shape in advance — simply doesn't need.
- HTTP caching stops working for free. REST GETs cache trivially at the CDN/browser level via URLs. GraphQL's single POST endpoint means you lose that for free and have to build response caching yourself (persisted queries help here).
Where REST still wins outright
Webhooks, file uploads, and anything that benefits from HTTP semantics (status codes, caching headers, simple curl-ability for debugging) are more natural in REST. A payment gateway sending you a webhook doesn't want to construct a GraphQL mutation — it wants to POST a JSON body to a URL and get a 200 back. I've never regretted keeping webhook receivers and admin-internal endpoints as plain REST even in an otherwise GraphQL-first system.
The hybrid that actually shipped
In practice, most of my production systems end up hybrid: a GraphQL API for the client-facing app where flexible querying genuinely matters (a dashboard with wildly different views per user role), and REST for everything else — webhooks, health checks, admin bulk operations, file uploads. Picking one paradigm for the entire system because "we chose GraphQL" is how you end up building a REST endpoint that pretends to be a GraphQL mutation just to accept a multipart file upload.
The honest recommendation
If your API has one primary client with well-known data needs, REST with well-designed, purpose-built endpoints will be simpler to build, cache, and debug. If you have multiple clients (web, mobile, partner integrations) with genuinely different data shape needs from the same underlying data, GraphQL's flexibility starts paying for its complexity. Don't adopt GraphQL because it's the API architecture of the moment — adopt it because you've already felt the specific pain it solves.