WierdX — Programming Reference All tutorials →
Developer reference · Practical tutorials · CS fundamentals
API Design

GraphQL vs REST: Choosing the Right API Query Model

Neither model is strictly better. REST gives you predictable, cacheable resources; GraphQL gives clients control over exactly what comes back. The right choice depends on who's calling your API and how varied their needs are.

Published July 6, 2026

REST organizes an API around resources: /users/42, /users/42/orders, each returning a fixed shape decided by the server. GraphQL flips that around — there's usually one endpoint, and the client sends a query describing exactly which fields it wants, across however many related objects, in a single request. The server exposes a schema; the client decides the shape of the response. That single sentence explains most of the trade-offs that follow.

The overfetching and underfetching problem GraphQL was built for

Picture a mobile screen that needs a user's name and avatar, plus the titles of their five most recent orders. With a REST API you typically either call /users/42 and /users/42/orders separately (two round trips, and the orders endpoint probably returns far more per-order data than the screen needs), or your backend team builds a bespoke aggregation endpoint just for this screen. Do that for every screen and you end up maintaining a pile of narrow, single-purpose endpoints. A GraphQL query for the same screen looks like this:

query {
  user(id: 42) {
    name
    avatarUrl
    orders(limit: 5) {
      title
      placedAt
    }
  }
}

One request, exactly the fields needed, no more and no less. That's the core pitch: overfetching (getting a full user object when you needed two fields) and underfetching (needing three requests to assemble one screen) both disappear because the client, not the server, decides the shape.

What that flexibility costs you

The server can no longer predict what a query will ask for, which breaks some things REST gets for free. HTTP caching relies on GET requests to stable URLs; GraphQL typically sends every query as a POST to the same endpoint, so a CDN or browser cache can't key on the URL the way it does for /users/42. Rate limiting and cost estimation get harder too — a deeply nested query that asks for every order, every line item, and every product on each line item can be far more expensive to execute than a single flat REST call, and a naive rate limiter that just counts requests won't catch it. Production GraphQL servers usually implement query cost analysis, complexity limits, or depth limits specifically to guard against this.

The N+1 problem lives here too

Resolving nested fields naively is a classic trap: fetching 20 users and then, for each one, issuing a separate database query for their orders turns one logical request into 21 database round trips. GraphQL servers solve this with batching utilities that collect all the pending "get orders for user X" calls issued during a single tick of the event loop and combine them into one batched database query, keyed by user ID. Skipping this step is the single most common reason a GraphQL API that felt fast in development gets slow in production under real, nested queries.

Where REST still wins outright

Simple CRUD APIs with a small, stable set of consumers don't need GraphQL's flexibility, and they lose real things by adopting it: standard HTTP caching, simpler tooling, and the ability to reason about an endpoint's cost just by reading its route. File uploads and binary responses are also cleaner over REST — GraphQL's JSON-in, JSON-out model handles them awkwardly, usually via multipart extensions bolted onto the spec rather than anything native. And for public APIs with many independent third-party consumers, REST's resource-oriented URLs tend to be easier for unfamiliar developers to explore and reason about than a schema they have to introspect first.

A practical way to decide

Ask how varied your clients' data needs actually are. A single web app with one team controlling both frontend and backend rarely needs GraphQL's flexibility badly enough to justify the added operational surface — query complexity limits, N+1 batching, cache-unfriendly responses. A platform serving a web app, a mobile app, and third-party integrations with genuinely different field needs per client is the case GraphQL was designed for. Several sizable engineering orgs have also landed on a hybrid: REST for public, cacheable, resource-shaped endpoints, GraphQL as an internal aggregation layer in front of those same services for screens that need to stitch several resources together in one round trip.