GraphQL
GraphQL is a query language for APIs. Instead of endpoints returning fixed shapes, there is one endpoint and a typed schema, and the client sends a query describing exactly the fields it wants. The response mirrors the query’s shape.
The problem it targets is real. With REST, a mobile client needing three fields from a station record receives whatever the endpoint returns — perhaps thirty fields, most unused. Needing related data means several round trips. Over a slow connection both matter, and the usual REST workaround is endpoint proliferation: /stations/42/summary, /stations/42/with-measurements, each a new thing to maintain.
GraphQL makes that the client’s decision. One query, one round trip, exactly the requested fields.
What it costs
The complexity moves; it does not vanish. Arbitrary client queries must be resolved efficiently by the server, and the naive implementation produces the N+1 problem: a query for 100 stations each with their measurements issues 101 database queries. DataLoader-style batching is the standard fix and it is required, not an optimisation — a GraphQL server without it will fall over.
Caching is harder. HTTP caching works on URLs and methods, and GraphQL is POST to one URL. Every layer of HTTP caching becomes useless, and the replacement is application-level caching in the client — which is exactly why Apollo and its normalised cache are effectively mandatory rather than optional tooling.
Query cost is unbounded. A client can request deeply nested data that is expensive or impossible to serve. Public APIs need query depth limits, complexity analysis, or persisted queries. This is a security consideration, not just performance.
When it is worth it
When clients genuinely differ in what they need — several frontends, third-party consumers, mobile alongside desktop — the flexibility earns its cost. The schema is also a strong contract, and code generation from it gives type safety comparable to generated REST clients.
When there is one frontend developed alongside the backend, it usually is not. The over-fetching GraphQL solves is a minor cost in that situation, and REST with a generated typed client delivers the same safety with far less machinery and working HTTP caching.
See also: REST, the comparison, Apollo, APIs, and schemas.