REST vs GraphQL comparison — over/under fetching, caching, developer experience, tooling, when GraphQL is worth the overhead, and when REST is still the right choice.
Here's a quick overview of how REST and GraphQL stack up across the most important decision criteria:
| Category | REST | GraphQL |
|---|---|---|
| Overfetching | Common (fixed response shape) | Never — request exactly what you need |
| Underfetching | Multiple endpoints per need | Multiple roundtrips without good design |
| Caching | Native HTTP caching (CDN, browser) | Complex — query-level caching needed |
| Learning Curve | Known by all developers | Moderate — schema, resolvers, etc |
| Tooling | Mature, universal | Good but heavier |
| File Uploads | Native multipart | Complex workaround required |
| Real-time | Via webhooks / SSE | Subscriptions built-in |
| Mobile Efficiency | Fixed responses | Request only needed fields |
| Schema/Docs | Manual (OpenAPI) | Schema is the documentation |
| Error Handling | HTTP status codes — universal | Always 200 OK — errors in body |
| Performance | Simpler, faster for simple cases | N+1 problem without DataLoader |
| Public API | Universal expectation | Less common |
Based on real-world usage, community feedback, and benchmark data, here's how each scores across key dimensions (out of 100):
GraphQL's primary selling point is eliminating over-fetching. But how much does it actually matter in practice?
For a simple mobile app showing a user profile, over-fetching can be significant — your REST endpoint might return 30 fields when the mobile UI only needs 5. On slow networks, this payload difference is real.
For a typical web application where you control both the frontend and API, over-fetching is usually solved by just creating more specific REST endpoints or using query parameters. The over-fetching problem is real, but it's also solvable with good REST API design.
// REST with specific endpoint
GET /api/users/123/summary
{"id": 123, "name": "Alice", "avatar": "..."}
// Or with field selection (sparse fieldsets)
GET /api/users/123?fields=id,name,avatar
{"id": 123, "name": "Alice", "avatar": "..."}
GraphQL introduces its own performance problem: the N+1 query. When resolving a list of posts with their authors, a naive implementation makes one query for posts, then one query per post for its author — N+1 database queries.
The solution is DataLoader — a batching library that collects all author IDs and fetches them in a single query. But this adds complexity that doesn't exist in well-designed REST endpoints.
Both REST and GraphQL have performance challenges — they're just different ones. REST's over-fetching vs GraphQL's N+1 risk.
Many teams adopt GraphQL for its technical elegance and then spend significant time solving caching and N+1 problems that REST doesn't have. Be honest about whether the data flexibility is worth the operational complexity for your specific case.