One of the most common decisions when starting a new project is this: REST vs GraphQL — which approach should you use to build your API layer? Both are mature, battle-tested ways of moving data between client and server, but they solve different problems in different ways. In this article I'll explain the core idea behind each approach, their strengths and weaknesses, practical topics like over/under-fetching and caching, and finally when you should pick which one.
The core idea behind each approach
REST models resources with URLs. Every resource has an address, and you act on it with HTTP verbs (GET, POST, PUT, DELETE). Typically /users/42 returns a user and /users/42/posts returns that user's posts. The server decides which fields to return.
GraphQL, on the other hand, is a query language that runs through a single endpoint (usually /graphql). The client states exactly which fields it wants in a query, and the server returns only those fields. So the side that decides the shape of the data is the client, not the server.
Let's compare the same data with both approaches. Fetching a user in REST:
GET /users/42
{
"id": 42,
"name": "Aslain",
"email": "hello@aslain.dev",
"createdAt": "2026-01-10"
}
Requesting only the name and email of the same user in GraphQL:
query {
user(id: 42) {
name
email
}
}
The response matches the requested shape exactly:
{
"data": {
"user": { "name": "Aslain", "email": "hello@aslain.dev" }
}
}
Over-fetching and under-fetching
GraphQL's most touted advantage revolves around these two concepts. Over-fetching means receiving more data than you need: in REST, /users/42 returns the name, email, signup date and maybe ten more fields, but if you only show the name, the rest was transferred for nothing.
Under-fetching means not getting enough data in a single request. To show a user and their last five posts in REST, you have to make two requests — first /users/42, then /users/42/posts. This is the N+1 request problem. In GraphQL you can request all of it nested in a single query:
query {
user(id: 42) {
name
posts(last: 5) { title publishedAt }
}
}
This is a real win, especially in mobile apps and on low bandwidth. But note: these problems can also be solved on the REST side. Field-selection parameters like ?fields=name,email reduce over-fetching, while embedding parameters like ?include=posts largely solve under-fetching. So what GraphQL solves isn't impossible in REST; it just requires design discipline.
Caching: where REST shines
Here the scales tip toward REST. REST is a perfect match for HTTP's native caching mechanisms. Because every resource has a unique URL, browsers, CDNs and reverse proxies (Nginx, Varnish, Cloudflare) can easily cache GET responses based on Cache-Control, ETag and Last-Modified headers.
In GraphQL, almost everything is a single POST /graphql request whose body differs every time. HTTP-level caching is therefore hard; you usually move caching to the client side (the normalized cache of libraries like Apollo Client, urql or Relay) or to server-side, field-level solutions (for example persisted queries). This is powerful but requires more setup.
Schema, types and developer experience
GraphQL has a strong type system. The schema is a contract: it explicitly defines which fields exist, their types and their relationships. Thanks to this:
- Automatic documentation: tools like GraphiQL or Apollo Studio generate live, browsable documentation from the schema.
- Type safety: with TypeScript code generators you get end-to-end types on the client side.
- One source, many screens: web, mobile and different clients all pull what they need from the same schema; the backend team doesn't have to open a new endpoint for every screen.
On the REST side you can get a similar guarantee with OpenAPI (formerly Swagger). The OpenAPI schema also provides documentation and client code generation; however, since the type system is inherent to GraphQL, this discipline comes more naturally there.
Complexity and things to watch out for
GraphQL doesn't come for free. The price of its flexibility is that you have to solve some problems yourself on the server side:
- The N+1 query problem: nested fields can fire many separate queries at the database. To solve this you need batching tools like
DataLoader. - Query cost: a client can strain the server by sending a very deep or very wide query. Query depth limiting and query cost analysis are essential.
- Caching and error handling: as noted above, HTTP caching is weak; also GraphQL returns
200 OKeven on failures and carries the error in theerrorsfield of the body, which changes how you monitor things.
REST wins on simplicity. HTTP status codes (404, 201, 401) are naturally meaningful, the tooling ecosystem is enormous, and almost every developer already knows REST. In small and medium projects this simplicity is often the right choice.
When should you choose which?
There's no hard rule, but these criteria make the decision easier:
- Choose REST: if your resources are clear and simple, if HTTP caching and CDNs are critical for you, if your team is familiar with REST, or if you're publishing a simple public API.
- Choose GraphQL: if you have many different clients (web + mobile) each wanting a different data shape, if nested relationships are complex, or if backend and frontend teams want to move fast and independently.
Remember: this isn't an either/or war. Many teams use both together — for example GraphQL for client-driven data aggregation and REST for file uploads, webhooks and third-party integrations. What matters is looking at the project's real needs, not ideology.
Frequently Asked Questions
Will GraphQL replace REST?
No. While GraphQL offers a smoother developer experience than REST in some scenarios, REST's simplicity and alignment with HTTP caching are still very valuable. The two have coexisted for years and will continue to; the right tool depends entirely on your use case.
Is GraphQL faster?
Calling it "faster" on its own is misleading. GraphQL can improve perceived client-side speed by reducing unnecessary data over the network and combining multiple requests into one query. But if N+1 queries aren't managed properly on the server, it can even be slower than REST. Speed depends on your architecture and optimization.
Should I migrate my existing REST API to GraphQL?
Rewriting a working REST API just because it's trendy is rarely sensible. If you're feeling real over/under-fetching pain or your client diversity has grown, adding GraphQL as a layer on top of the existing REST (a gateway approach) is often the smarter path.
Want to get your API architecture right? If you need help designing a scalable API with REST or GraphQL on the Laravel and Node.js side, get in touch with me — let's pick the best approach for your project together.