REST or GraphQL for your web or mobile product? Compare caching, flexibility, complexity and team fit, with practical design tips.
In this article
Choose REST when your API is made up of clear resources, you want simple caching and tooling, and your clients have similar needs. Choose GraphQL when many different clients, such as web, mobile and partner apps, need different shapes of the same data, or when screens must combine data from many sources in one request. Neither is better in general. For a first version of most business products, a well-designed REST API is the lower-risk default, and GraphQL can be added later where it earns its place.
Both are ways for a front end to talk to a back end over HTTP. The difference lies in who decides what data comes back: the server (REST) or the client (GraphQL). That single difference drives most of the trade-offs.
How REST works
REST organises an API around resources, each with a URL, and uses standard HTTP methods: GET to read, POST to create, PUT or PATCH to update, DELETE to remove. Each endpoint returns a fixed shape.
GET /api/customers/42
GET /api/customers/42/orders?status=open
Because it uses plain HTTP, REST benefits from everything the web already provides: browser and CDN caching, status codes, standard authentication headers, and tools like curl and Postman. Documentation is commonly written in the OpenAPI format, which can also generate client code and tests.
Where REST struggles
- Over-fetching. An endpoint may return fields the screen does not need.
- Under-fetching. A screen may need several endpoints, forcing multiple round trips (a customer, then their orders, then each order's items).
- Endpoint sprawl. Special-purpose endpoints multiply as client needs diverge.
How GraphQL works
GraphQL exposes a typed schema through (usually) a single endpoint. The client sends a query describing exactly the fields it wants, and receives exactly that shape:
query CustomerOverview {
customer(id: 42) {
name
email
orders(status: OPEN) {
id
total
items { sku quantity }
}
}
}
One request can replace several REST calls, and different clients can ask for different fields without the back end creating new endpoints. The schema doubles as living documentation, and tooling can validate queries before they run.
Where GraphQL struggles
- Caching. Most requests are
POSTto one URL, so standard HTTP caching does not apply directly. You rely on client-side caches and persisted queries. - Query cost. A client can write a deeply nested or very broad query that is expensive to resolve. You need depth limits, complexity limits and timeouts.
- The N+1 problem. Naive resolvers run one database query per item in a list. Batching tools such as DataLoader address this, but someone must apply them.
- More moving parts. Schema design, resolvers, authorisation per field and error handling all need care.
Side-by-side comparison
| Aspect | REST | GraphQL |
|---|---|---|
| Data shape | Fixed by the server | Chosen by the client |
| Round trips for a complex screen | Often several | Often one |
| HTTP caching | Works naturally | Needs extra approach |
| Learning curve | Low | Moderate |
| Documentation | OpenAPI | Schema introspection |
| File uploads | Straightforward | Possible, needs conventions |
| Error handling | HTTP status codes | Usually 200 with an errors array |
| Public third-party API | Familiar to most developers | Needs more protection against costly queries |
| Best for | Resource-oriented services, simple integrations | Varied clients, complex relational screens |
Questions to ask before choosing
- How many different clients will consume this API? One web front end and one mobile app with similar screens rarely need GraphQL. Many clients with diverging needs do.
- How complex are your screens? If a single view combines data from many entities, GraphQL can simplify the client.
- Who will consume the API? If external partners will integrate, REST is familiar and easier to support.
- How important is HTTP caching? Content that is public and cacheable favours REST.
- What does your team know? Experience reduces mistakes more than a theoretical advantage does.
- What are your authorisation rules? GraphQL needs checks at field and object level; plan this early.
Practical design tips for REST
- Use nouns for resources (
/orders), not verbs (/getOrders). - Return correct status codes:
201for creation,400for invalid input,401or403for access problems,404when missing. - Paginate list endpoints from the start, and support filtering and sorting.
- Version deliberately, for instance
/v1/in the path or in a header, and do not break existing clients silently. - Offer field selection or compact and detailed variants where over-fetching hurts.
- Publish an OpenAPI description and keep it in step with the code.
Practical design tips for GraphQL
- Design the schema around your domain, not your database tables.
- Limit query depth and complexity, set timeouts, and consider persisted queries for production clients.
- Batch data loading to avoid N+1 query patterns.
- Enforce authorisation in resolvers or a shared layer, not only at the entry point.
- Disable or restrict introspection and verbose errors on public production endpoints where appropriate.
- Return structured error information so clients can react to specific failures.
Authorisation and rate limiting matter for both styles; our guide to a secure login system covers the identity side.
What it means for your budget and timeline
REST is quicker to start with because developers, testing tools, monitoring products and API gateways all assume it. A competent team can have a working first version of an API within days of agreeing the data model. GraphQL asks for more up-front thought about the schema and about guarding against expensive queries, but it can repay that investment when the front end changes often, because front-end developers can adjust the data they request without waiting for new endpoints. The saving appears over months of iteration, not in the first sprint.
Also think about who writes the client code. If a separate team builds the mobile app, a typed GraphQL schema or an OpenAPI description gives them a precise contract to work from. Without either, the contract lives in people's heads, and the two teams find mismatches late.
Can you use both?
Yes, and it is common. A team might offer REST for simple integrations and webhooks, and GraphQL as a gateway that aggregates several back-end services for its own web and mobile apps. This is often an evolution rather than a starting design: begin with REST, notice where screens need awkward chains of calls, and add a GraphQL layer in front for those parts. If you are building services in the style discussed in monolith vs microservices, a GraphQL gateway can hide the internal service boundaries from clients.
Common mistakes
- Picking GraphQL for fashion. If you have one client and simple screens, you may add complexity without payoff.
- Calling an API "REST" while it is really remote procedure calls. Endpoints like
/doEverythinglose the benefits of the style. - No pagination. A list that returns everything works in testing and fails with real data.
- Exposing your database schema directly. It couples clients to internals and makes change painful.
- Ignoring query cost in GraphQL. One expensive query from a client can slow the system for everyone.
- Inconsistent error formats across endpoints, which forces clients to special-case everything.
- Skipping documentation and contract tests. The API is a product for other developers, so treat it like one.
Getting your API right
The API is the contract between your front end, your mobile apps and often your partners. Changing it later is expensive, so a short design phase is worthwhile. Our web application development service includes API development in both REST and GraphQL, with documentation as a deliverable, and we can help you decide which suits your product before anything is built.
Share this article
General educational information, not legal or professional advice for your specific situation.
