GraphQL was released open-source by Facebook in 2015 and has had three to four years of serious enterprise adoption. The production patterns are clearer now than they were at initial adoption: where GraphQL genuinely improves on REST, and where its complexity costs exceed its benefits.

The genuine improvements

GraphQL's core value proposition is client-controlled data fetching: the client specifies exactly what fields it needs and receives exactly that, nothing more. For applications with multiple frontends (web, mobile, third-party integrations) that need different subsets of the same data, GraphQL eliminates over-fetching and the proliferation of REST endpoint variants. The type system provides machine-readable schema documentation and enables powerful developer tooling.

The N+1 query problem

The most common production issue with GraphQL is the N+1 query problem: a list query that resolves a nested field triggers one database query per list item rather than a single batched query. The standard solution is DataLoader (from Facebook), a batching and caching layer that defers field resolution and groups database calls. Every production GraphQL implementation needs DataLoader or an equivalent. Getting this wrong produces catastrophic database performance under load.

Depth and complexity limiting

GraphQL allows clients to request arbitrarily nested queries. Without limits, a malicious or poorly written query can trigger recursive joins that bring down the database. Production GraphQL APIs need query depth limits (typically max depth of 5-10), complexity analysis (assign cost to each field, reject queries above a cost threshold), and rate limiting. The attack surface is different from REST, a GraphQL server needs explicit protection against query abuse.

The federation pattern

Apollo Federation allows a GraphQL schema to be composed from multiple downstream services, each owning a portion of the graph. The federated gateway stitches the schema together and routes queries to the appropriate services. This is the enterprise pattern for large organisations: each team owns their domain's GraphQL schema, and the unified graph is assembled at the gateway. The operational complexity of running a federated gateway is real but manageable.