im·a·cto
← choices

$ cat choices/graphql.md

GraphQL

the call

I reach for GraphQL when the client owns the shape and many surfaces hit one graph. It's worth the complexity then; it's overkill when one client talks to one backend.

why

GraphQL earns its keep when the client owns the shape of the data and you have more than one client. Two mobile apps and a web surface all asking the same backend for slightly different cuts of the same entities is exactly the problem it solves. One graph, every client declares what it needs, nobody ships a custom endpoint per screen. That’s the case. REST handles the rest.

when I don’t

One client talking to one backend doesn’t need a graph. It needs an endpoint. GraphQL drags in a schema, a type system, resolvers, caching semantics, and N+1 footguns the day you turn it on. If you only have one surface, you’re paying the whole tax to solve a problem you don’t have. It’s the textbook résumé-driven trap. The architecture diagram looks impressive and the app would’ve shipped faster with plain JSON over REST.

in production

GigSmart runs two React Native apps and a web client against one graph, the case where GraphQL actually earns its complexity, because each client owns the shape it needs from shared entities. For the client layer I went with Relay over Apollo. The reasoning: Relay’s compiler enforces fragment colocation, so every component declares exactly the data it consumes and the compiler stitches those fragments into one optimized query per screen. That’s a guardrail. It structurally prevents the over- and under-fetching that quietly rots a large multi-client codebase. Apollo is easier on day one and sprawls on day three hundred. Relay is the “build the tracks” choice: more upfront discipline (compiler, fragments, a normalized store) for a client that’s going to scale across surfaces. The train only moves as fast as the tracks it’s built on, and Relay lays better track.— see: works / GigSmart

the principle under it

Complexity is only worth it when it buys you a guardrail you’ll actually lean on. A graph for one client is overhead; a graph for many clients is leverage, but only if the tooling enforces the discipline instead of trusting everyone to remember it. Autonomy with guardrails beats autonomy on the honor system every time, because the honor system fails silently and you find out in a perf review three quarters later.

the gaps — what it costs even when it’s right

The N+1 problem is now yours. A graph that lets clients ask for anything will happily fan one query into a hundred database calls. Resolvers, batching, and dataloaders are table stakes, not nice-to-haves, and they’re invisible until something’s slow.

Relay’s discipline has a learning curve. Fragment colocation and the compiler are exactly the point, but they’re also the ramp. New engineers don’t get it for free. You’re buying long-term structure with short-term onboarding friction.

Caching and auth get harder, not easier. HTTP caching mostly evaporates when everything’s a POST to one endpoint, and field-level authorization is something you have to design in. The graph moves those problems; it doesn’t delete them.

© 2026 — written by a human, with help, and said so canonical jasonwaldrip.com · delivered through The Bushido Collective