The problems GraphQL solves are over-fetching and request multiplication. A mobile screen that needs a user's name and their three latest orders should not download entire embedded objects or make four round trips. The schema doubles as a typed contract — introspectable, versionable by deprecation rather than by breaking change, and able to generate typed client code, which removes a whole category of integration drift.
The costs are real and specific. Naive resolvers produce the N+1 query problem — one database query per item per field — which DataLoader-style batching exists to solve. HTTP caching no longer works, so caching moves to persisted queries and response-level strategies. Rate limiting by request count stops meaning anything, because one query can be cheap or catastrophic; production servers limit query depth and compute a cost score per query instead.
GraphQL earns its complexity when several clients with different data needs share one API — web and mobile pulling different shapes from the same graph is the canonical case. For simple CRUD, cache-heavy public APIs, file transfer and webhooks, REST remains simpler and better tooled. The decision is about client diversity and data shape heterogeneity, not about which is newer.
At larger scale, federation composes one graph from subgraphs owned by different teams, so the payments team ships its schema without coordinating every release with every other team. It solves an organisational problem rather than a technical one, and it prices accordingly — a federated gateway is infrastructure that needs operating, monitoring and versioning. Below a certain team count, a single well-governed schema is simpler to run and faster to evolve, and federation adopted for the architecture diagram rather than the org chart is complexity purchased without a customer.
The schema is a product surface and should be run like one. Fields are deprecated rather than deleted, breaking-change detection runs in CI against the composed schema, and usage telemetry shows which clients still call a field before it is retired. Teams that treat the schema casually learn the hard way that GraphQL's flexibility makes fields easy to add and socially impossible to remove — the graph becomes an attic unless someone owns it.
Codazz builds this in production — API & Backend Development.