GraphQL was launched by Facebook in 2015 and has since been the "modern" choice for API design. But after building APIs in both paradigms, our honest assessment is: most projects don't need GraphQL.
What's the difference?
REST: Resource-based
REST exposes endpoints for each resource:
The server determines which fields are returned.
GraphQL: Query-based
GraphQL has one endpoint where the client specifies exactly what it wants:
query {
user(id: 123) {
name
email
orders {
id
total
}
}
}The client determines the structure.
When GraphQL makes sense
GraphQL solves real problems - just not the problems you probably have.
Use GraphQL when:
1. You have many different clients with vastly different data needs
Facebook has iOS, Android, web, React Native, embedded devices - all with different screens and data needs. One flexible API makes sense.
Do you have that? Probably not. Most have one webapp and maybe one mobile app.
2. You have deeply nested, relational data with complex queries
Social networks, content management systems, or e-commerce with thousands of product variants.
3. Your frontend team wants full control over data
GraphQL gives frontend developers freedom to fetch exactly what they need without waiting for backend changes.
4. You have a dedicated API team
GraphQL requires more infrastructure: schema management, query complexity analysis, caching strategy, performance monitoring.
Use REST when:
1. You're building a standard webapp or mobile app
CRUD operations, user management, simple relations. REST does it with less complexity.
2. You have one or two client types
If all your clients use the same data roughly the same way, GraphQL solves a problem you don't have.
3. Caching is important
REST's HTTP-based caching (CDN, browser cache, etags) works out-of-the-box. GraphQL's POST requests don't cache automatically.
4. Your team is small
GraphQL has a learning curve and maintenance costs. Small teams get more out of simple REST.
The hidden costs of GraphQL
1. N+1 Problem
The classic GraphQL trap:
query {
users {
name
posts {
title
}
}
}Without DataLoader, this makes one query for users + one query per user for posts. 100 users = 101 database queries.
Solution: DataLoader, but that's extra complexity you have to build and maintain.
2. Caching is hard
REST:
Browser and CDN cache automatically with Cache-Control headers.
GraphQL: All requests are POST to the same endpoint. You need to implement:
- Persisted queries
- Apollo Client cache
- Server-side caching with Redis
- Cache invalidation strategy
3. Rate limiting and security
REST: Limit requests per endpoint. Simple.
GraphQL: A single query can be cheap or extremely expensive:
query {
users {
posts {
comments {
author {
posts {
comments {
# Nested doom
}
}
}
}
}
}
}You need to implement query depth limiting, complexity analysis, and timeout handling.
4. Error handling
REST: HTTP status codes. 404 = not found. 401 = unauthorized. Everyone understands it.
GraphQL: Everything returns 200 OK. Errors are hidden in response body under errors array. You have to parse and handle it yourself.
5. Tooling and debugging
REST: Any HTTP client works. curl, Postman, browser DevTools.
GraphQL: You need specialized tools like GraphiQL or Apollo Studio to be productive.
Performance comparison
| Aspect | REST | GraphQL |
|---|---|---|
| Over-fetching | Yes, server decides | No, client decides |
| Under-fetching | Yes, multiple requests | No, one request |
| Caching | Built into HTTP | Must be implemented |
| Request overhead | Minimal | Query parsing + validation |
| N+1 queries | Rare problem | Common problem |
Over-fetching (getting too much data) is GraphQL's main argument. But in practice:
- JSON parsing is fast
- Gzip compresses well
- You can make separate REST endpoints for specific views
Our recommendation
Start with REST. Always.
- Simple to understand - everyone knows HTTP verbs and status codes
- Simple to cache - CDN and browser cache work automatically
- Simple to secure - rate limiting per endpoint
- Simple to document - OpenAPI/Swagger is industry standard
- Simple to debug - curl and browser DevTools
Consider GraphQL when:
- You have 3+ different client platforms with different data needs
- Your frontend team is constantly blocked by backend changes
- You have a dedicated API team to maintain the infrastructure
- Over-fetching is a measurable performance problem, not theoretical
The BFF pattern: Best of both worlds
Many teams use Backend for Frontend (BFF) instead of GraphQL:
Mobile App → Mobile BFF → Services
Web App → Web BFF → ServicesEach BFF is a thin REST API that aggregates exactly the data the client needs. You get:
- Client-specific data without GraphQL complexity
- Simple HTTP caching
- No new query language to learn
Conclusion
GraphQL is a fantastic tool - for the problems it solves. But "everyone uses it" is not a good reason to choose it.
Ask yourself:
- Do I really have many different clients with vastly different needs?
- Is over-fetching a measurable problem in my app?
- Do I have resources to build and maintain GraphQL infrastructure?
If the answer is no, then REST is the right choice. It's not old-fashioned - it's pragmatic.