Handbooks  /  GraphQL vs REST
Engineering~9 min readComparison
Head to Head

GraphQL vs REST: who picks the shape of the data?

GraphQLvsREST

REST hands you a menu of fixed dishes; GraphQL hands you the ingredients and lets each client cook exactly the plate it wants. That single difference — server-decided shape vs client-decided shape — cascades into everything else: over-fetching, caching, versioning, and the failure modes each one is prone to.

01

The one distinction that decides everything

REST models your API as a set of resources, each at its own URL (/users/42, /users/42/posts), and the server decides what fields each endpoint returns. GraphQL exposes a single endpoint (/graphql) and a type schema, and the client writes a query saying exactly which fields of which resources it wants — the server assembles precisely that shape in one response.

→ The rule

If the server should own the response shape and you want simple, cacheable, resource-oriented endpoints, REST fits. If many different clients each need a different slice of deeply-related data and you want them to ask for exactly that in one round trip, GraphQL fits.

02

Head to head

DimensionRESTGraphQL
EndpointsMany, one per resourceOne (/graphql), a typed schema behind it
Response shapeFixed by the server per endpointChosen by the client, per query
Over/under-fetchingCommon — fixed payloads, multiple calls to assemble a viewSolved — ask for exactly the fields you need, across resources, at once
HTTP cachingFree — GET + stable URL caches in browsers, CDNs, proxiesHard — single POST endpoint bypasses URL caching; needs app-layer caching
VersioningExplicit — /v2/, breaking changes ship new URLsEvolve the schema — deprecate fields instead of versioning
Typing & introspectionConvention (OpenAPI adds it on)Built-in — a typed schema, introspectable, self-documenting
Error handlingHTTP status codes (404, 500…)Usually HTTP 200 with an errors array; partial data is normal
Server complexityLow — each route is a handlerHigher — resolvers, schema, and the N+1 problem to manage
Classic failure modeThe mobile app makes 6 calls and still over-fetchesOne innocent query fans out into N+1 database hits
03

When to use each

Reach for REST

  • A public API many third parties consume (predictable, cacheable, familiar)
  • Simple, resource-shaped CRUD without deep nesting
  • You want HTTP caching, CDNs and standard status codes for free
  • File uploads/downloads and streaming, which REST handles naturally
  • A small team that doesn't want to run a schema + resolver layer

Reach for GraphQL

  • Many clients (web, iOS, Android) each needing a different data shape
  • Deeply nested, related data assembled per screen (feeds, dashboards)
  • You're tired of shipping a new endpoint every time the UI changes
  • A gateway aggregating several backend services behind one schema
  • Fast-moving product teams that want the client to drive the query
04

The answer is often "REST underneath, GraphQL at the edge"

These aren't mutually exclusive. A very common production shape is REST (or gRPC) between internal services — where simple, cacheable, independently-deployed endpoints shine — with a GraphQL gateway in front, aggregating those services into one client-facing schema so the web and mobile apps get exactly-shaped data in a single round trip. The clients get GraphQL's ergonomics; the backend keeps REST's simplicity and caching. You don't have to pick one for the whole system.

→ The cheap default

Start with REST. It's simpler, its caching is free, and most APIs are resource-shaped enough that it's genuinely the right tool. Reach for GraphQL when you can point at a concrete pain — multiple clients over-fetching, or a screen that needs five REST calls to render — not because it's newer.

05

The caching and N+1 reality nobody mentions in the demo

GraphQL's flexibility has two costs the tutorials skip. First, caching: REST rides on HTTP, so a GET /users/42 is cached for free by the browser, the CDN and any proxy in between. GraphQL sends every query as a POST to one URL, so that entire layer of free caching evaporates — you rebuild it in the application with persisted queries, a normalized client cache (Apollo, urql), and server-side response caching keyed on the query, not the URL.

Second, the N+1 problem: a query for 50 posts, each with its author, can trigger a naive resolver to run 1 query for the posts and then 50 more for the authors — 51 database hits for one request. The fix is DataLoader, which batches every author lookup in a single tick into one IN (...) query and caches results per request. It's a solved problem — but it's a problem you have to know exists, whereas REST's fixed endpoints rarely surprise you this way.

→ The trade you're actually making

GraphQL moves work from the client (which no longer over-fetches or makes many round trips) onto the server (which now owns schema design, resolver batching and a caching strategy HTTP used to give you for free).

06

A worked scenario: a public weather API vs a social feed app

A public weather API — GET /forecast?city=London — is a textbook REST case: the resource is simple, the response shape is stable, thousands of clients want the same data, and CDN caching a popular city's forecast for a few minutes is a massive, free win. Wrapping that in GraphQL would add a schema, resolvers and a caching headache to solve a problem REST already handles perfectly.

A social app's home feed is the opposite. One screen needs the current user, their feed of posts, each post's author, like count, top comments and each commenter's avatar — five or six related resources, nested, and the iOS app wants slightly different fields than the web app. In REST that's a waterfall of calls or a bespoke /feed endpoint you re-cut every time the design changes. In GraphQL it's one query per client, each asking for exactly its fields — with DataLoader batching the author and comment lookups so "one query" doesn't quietly become N+1 behind the scenes.

→ The pattern generalizes

Stable, cacheable, one-shape-fits-all data → REST. Many clients, deeply nested and varied per screen → GraphQL. Big systems usually have both shapes, which is why "REST services behind a GraphQL gateway" is so common.

Frequently asked

Quick answers

GraphQL or REST — which should I use?

Decide by who needs to control the response shape. For a simple, public, cacheable API with stable resources, REST is simpler and its HTTP caching is free. For an app with many clients fetching deeply nested, varied data, GraphQL lets each client ask for exactly what it needs in one round trip. Many teams run both: REST for public/simple endpoints, GraphQL as a client-facing gateway.

What problem does GraphQL actually solve?

Over-fetching and under-fetching. A fixed REST endpoint returns a fixed shape, so a mobile screen often gets more fields than it needs, or has to call three endpoints to assemble one view. GraphQL lets the client request exactly the fields it wants, for multiple resources, in a single request.

Why is caching harder with GraphQL?

REST rides on HTTP — a GET to a stable URL is cached for free by browsers, CDNs and proxies. GraphQL usually POSTs every query to one endpoint, so URL-based caching doesn't apply. You recover it at the app layer: persisted queries, a normalized client cache, and DataLoader on the server.

What is the N+1 problem in GraphQL?

A query for a list plus a field on each item that needs its own lookup (50 posts, each with an author) can fire 1 + N queries. The standard fix is DataLoader, which batches all the lookups from one tick into a single query and caches them per request.

GraphQL vs REST · Vibe Engines · 2026
Finished this one? 0 / 139 Handbooks done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

Cite this page

Reference it in your work, paper or an AI's context window.

APASingh, S. (2026). GraphQL vs REST. Vibe Engines. https://vibeengines.com/handbook/graphql-vs-rest
MLASingh, Saurabh. “GraphQL vs REST.” Vibe Engines, 2026, vibeengines.com/handbook/graphql-vs-rest.
BibTeX
@online{vibeengines-graphql-vs-rest,
  author       = {Singh, Saurabh},
  title        = {GraphQL vs REST},
  year         = {2026},
  organization = {Vibe Engines},
  url          = {https://vibeengines.com/handbook/graphql-vs-rest}
}