GPT-5.6 Sol · Claude Opus 5 · Gemini 3.1 Pro
Round 1REST, GraphQL, or tRPC for a new SaaS API in 2026? TypeScript across the stack, small team, a public API planned within a year. Pick one and defend it, not "it depends".
Initial answers
Moderator summary
Choose OpenAPI-first REST: it preserves TypeScript velocity without forcing a public API migration
REST is the strongest choice because the public API—not the internal TypeScript stack—is the binding constraint.
- Public-contract durability: External consumers may use Python, Java, Kotlin, Go, or plain HTTP, so a protocol-native HTTP contract avoids having to expose or later replace a TypeScript-specific RPC surface. REST also fits standard authentication, pagination, idempotency, webhooks, rate limits, caching, and versioning conventions.
- Internal developer experience: Use a typed contract layer such as
ts-rest, oRPC, or generated TypeScript clients from OpenAPI. Claude specifically recommends oRPC when RPC-style ergonomics and a first-class OpenAPI surface are both wanted, andts-restwhen the contract should look like HTTP from day one (Claude Opus 5). Hono or Fastify are reasonable runtime choices (GPT-5.6 Sol; Claude Opus 5; Gemini 3.1 Pro). - Implementation rule: Make the contract executable and generated rather than hand-maintained. Dogfood it with the frontend, establish
/v1/, cursor pagination, stable error codes, request IDs, authentication scopes, and idempotency conventions before outside users arrive (Claude Opus 5). Keep business logic independent of HTTP handlers (GPT-5.6 Sol). - Why not GraphQL: The panel agrees that GraphQL’s main payoff—heterogeneous clients with substantially different, nested data needs—does not obviously justify resolver, N+1, query-cost, authorization, and caching complexity for a small team. Purpose-built compound endpoints or
?include=can address isolated over-fetching cases (Claude Opus 5). - Important qualification: The panel differs on how closely modern typed REST tooling matches tRPC. Gemini calls the experience “exactly the same,” while Sol treats it as slightly less frictionless; the practical recommendation remains REST, but that DX claim should not be accepted without testing the chosen stack.
The result is one HTTP surface that the frontend consumes first and external developers can use later, rather than an internal tRPC surface followed by a public translation project.
Disagreements
TypeScript DX parity: Gemini says typed REST tools provide “the exact same developer experience” as tRPC, and Claude describes “tRPC-grade type safety”; Sol says OpenAPI-generated typing is valuable but “less frictionless than tRPC inference.”
Strength of the tRPC objection: Claude makes the categorical claim that tRPC “doesn't work for public APIs,” whereas Sol’s narrower position is that it is excellent internally but likely creates a later rebuild or wrapper when non-TypeScript consumers arrive.
Blind spots
Actual public audience: All three assume the public API will need non-TypeScript clients and ordinary HTTP interoperability; none establishes whether the first year’s customers, partners, or SDK targets actually require that. An exclusively TypeScript audience could materially weaken REST’s decisive advantage.
API workload shape: None tests the expected read patterns, relationship depth, or number of heterogeneous clients. Highly nested, client-specific reads could make GraphQL worth its operational cost; a mostly resource-oriented SaaS domain would reinforce REST.
GPT-5.6 Sol
Pick REST—specifically, an OpenAPI-first REST API.
Your public API planned within a year is the decisive constraint. Design the contract you will eventually expose, then use that same API internally from day one.
Why REST wins
- No future rewrite. tRPC is excellent inside an end-to-end TypeScript boundary, but external consumers may use Python, Java, Kotlin, Go, or plain HTTP. Adopting tRPC now would likely mean rebuilding or wrapping those procedures when the public API launches.
- Strong typing is still available. Define the API in OpenAPI and generate TypeScript clients and server types. It is less frictionless than tRPC inference, but preserves most of the practical type-safety benefit without coupling consumers to your repository.
- Better public-API ergonomics. REST has mature conventions and tooling for authentication, rate limits, pagination, idempotency, caching, webhooks, versioning, SDK generation, and interactive documentation.
- A stable contract from the beginning. Your frontend becomes the first real consumer of the public API, exposing awkward resource models and missing operations before partners depend on them.
- GraphQL solves the wrong problem. Unless you already have multiple backends or clients with substantially different, unpredictable data requirements, GraphQL adds schema governance, resolvers, N+1 risks, authorization complexity, and custom caching without enough payoff.
The key distinction is who must consume the API: tRPC assumes shared TypeScript types, while REST assumes callers do not share your code. That makes REST the durable choice for external consumers duskolicanin.com. Another 2026 comparison similarly recommends REST when external consumers are expected and warns that switching later touches every API call jagatjeet.com.
How I’d implement it
- Treat OpenAPI as the source of truth.
- Generate the TypeScript client used by your own frontend.
- Use resource-oriented endpoints, but allow pragmatic action endpoints where appropriate.
- Establish pagination, error envelopes, idempotency, authentication, and versioning conventions immediately.
- Keep business logic outside HTTP handlers so transport details do not infect the domain layer.
You will sacrifice some of tRPC’s near-zero-effort type inference. That is a worthwhile cost: build the API you know you’ll need, rather than optimizing for twelve months and then maintaining two API surfaces.
Claude Opus 5
Verdict: REST, OpenAPI-first — implemented with a typed contract layer (oRPC or ts-rest)
One wire protocol, one contract, one thing to version. You get tRPC-grade type safety inside your monorepo and a spec you can hand to a stranger, without maintaining two API surfaces.
Why tRPC loses, given a public API in 12 months
tRPC is excellent at exactly one job: a TypeScript client you own talking to a TypeScript server you own. The moment external developers show up, its core assumption breaks. Client and server must share a TypeScript codebase; tRPC doesn't work for public APIs, third-party integrations, or non-TypeScript clients — and as RPC, there are no resource URLs, no HTTP caching at the URL level, no standard clients. OpenAPI is an add-on rather than the native model, so public APIs feel grafted on.
The counter-argument is "just bolt on trpc-openapi later." That's how you end up with two APIs, two auth paths, two rate limiters, and a spec that's a lossy projection of your real one. If you know the public API is coming, don't design yourself into a migration you've already scheduled. Switching paradigms later is expensive — choose on a two-year horizon.
Bonus: tRPC's router type inference scales with router size, and very large routers slow down tsc — a real tax on a small team's iteration speed.
Why GraphQL loses for a small team
GraphQL's payoff is many heterogeneous clients with divergent data needs. You have one frontend and a handful of integrators. What you'd buy instead is a permanent operational tax: per-field authorization, N+1 resolution and dataloaders, query cost analysis and depth limiting to keep a public endpoint from being a DoS vector, no free HTTP/CDN caching, and a schema you can add to but never really remove from. That's a platform team's job description, not a side quest. Adoption reflects this: GraphQL sits at roughly 25% of enterprise teams, down from a ~40% peak, concentrated in orgs with complex frontend data requirements and multiple client platforms. You are not that org.
Why REST wins on the dimensions you actually care about
- Integrator onboarding.
curl https://api.example.com/users/123is simpler than explaining GraphQL queries or tRPC types to a developer evaluating your API. - Free infrastructure. URL-level caching, CDNs, idempotency keys, per-endpoint rate limits, standard bearer auth, HTTP status semantics, every proxy and observability tool ever built.
- SDKs and docs for free. OpenAPI 3.1 → generated clients in TS/Python/Go, plus Scalar or similar for docs. OpenAPI 3.1 and HTTP/3 have only strengthened REST's position.
- Agents and LLM tooling. LLM tool calls expect JSON Schema-shaped REST, which OpenAPI 3.1 gives you directly since it's JSON Schema-aligned. In 2026 that's a distribution channel, not a nice-to-have.
- Webhooks. You're shipping REST endpoints for webhooks regardless.
The concrete stack
Define Zod schemas once, derive everything: oRPC if you want RPC-style DX with a first-class spec, ts-rest if you want the contract to look like HTTP from day one. oRPC is OpenAPI-first and contract-first, best when you need both end-to-end TS types and an OpenAPI surface for third parties; ts-rest is REST-shaped — "we're shipping HTTP endpoints anyway, just make them typed" — with the cleanest non-TS interop. Both are also faster to typecheck: the contract is a plain object that doesn't infer through nested procedures.
Runtime: Hono (portable across Node/Bun/Workers) or Fastify. oRPC can serve a typed RPC endpoint, a REST/OpenAPI endpoint, a generated spec, and rendered docs off the same router — all from one contract, with the OpenAPI spec generated directly from the implemented router.
Rules that make this hold up
- Version at the URL (
/v1/) from commit one, even while you're the only consumer. Free now, impossible to retrofit politely. - Cursor pagination everywhere, never offset. You will not get to change this after publishing.
- Spec is generated, never hand-written. A hand-maintained OpenAPI file drifts within weeks — that's the one legitimate knock on REST: type safety across the boundary is only as good as your OpenAPI discipline.
- Design the public shape now, publish later. Same endpoints, gated behind API keys and scopes. Your frontend becomes consumer #1 and dogfoods the contract for a year before strangers touch it.
- Stable error envelope with machine-readable codes, plus request IDs. Integrators depend on your errors as much as your successes.
The honest cost
You'll write more per-endpoint plumbing than a tRPC monorepo, and your frontend will occasionally over-fetch or make two calls where GraphQL would make one. That's the price. Compound-query pain is solvable with a purpose-built endpoint or ?include= when it actually hurts; a wrong protocol choice with paying integrators on it is not solvable at all.
Gemini 3.1 Pro
Choose REST, implemented with a modern TypeScript-first framework (like ts-rest, Hono, or Elysia). It is the only option that delivers high-velocity internal type safety today without creating massive technical debt for your public API tomorrow.
The public API tiebreaker: Because you are launching a public API within a year, REST is the undisputed best choice. External developers expect standard HTTP endpoints and webhook-friendly architectures. tRPC is useless to non-TypeScript consumers, which would force your small team to build and maintain an awkward OpenAPI translation layer. GraphQL forces third-party developers to learn your specific schema and adopt heavier client libraries just to make basic requests.
Internal DX now matches tRPC: The historical advantage of tRPC was flawless, end-to-end TypeScript inference without code generation. Today, modern REST tools provide the exact same developer experience. By defining your routing contract with validation libraries like Zod, you get a fully typed, auto-completing client for your frontend. You get the strict type safety of tRPC without locking yourself into an RPC-only architecture.
Small team velocity: GraphQL routinely bogs down small teams. It requires complex resolver logic, DataLoader setups to avoid N+1 query performance issues, and highly intricate rate-limiting to prevent malicious nested queries. REST keeps the architecture fundamentally simple. You can rely on standard HTTP caching, straightforward endpoint-based rate limiting, and traditional web security middleware.
Zero-effort public documentation: By utilizing a modern TypeScript REST approach, your code automatically generates a strict OpenAPI (Swagger) specification based on your types. When the time comes to flip the switch on your public API, your interactive developer documentation and multi-language client SDKs will already be complete and perfectly synchronized with your backend.
Follow-up 1
Moderator summary
Choose OpenAPI-first REST; test its contract tax, and reserve GraphQL for measured query-shape pain
The round moved toward a firmer REST recommendation while narrowing the remaining uncertainty.
- What changed: Gemini explicitly conceded that typed REST is not exactly as frictionless as tRPC and accepted a per-endpoint “contract tax.” Claude withdrew an unsupported GraphQL adoption figure, while Sol supplied a concrete way to test the remaining DX gap rather than argue from intuition.
- Implementation decision: Use an executable, contract-first REST layer such as oRPC or ts-rest, generate OpenAPI 3.1 and non-TypeScript SDKs, and keep business logic separate from transport handlers. Sol’s two-day benchmark should cover CRUD, cursor pagination, nested reads, uploads, idempotent mutations, typed errors, auth scopes, and webhooks.
- Acceptance gate: Adopt the REST tool only if schemas are authored once, breaking changes propagate through server and clients, runtime validation remains enforced, generated artifacts are checked in CI, and the edit-to-autocomplete loop is no more than roughly 20% slower than tRPC. These are Sol’s proposed thresholds, not independently verified industry standards.
- Public-contract rationale: Typed REST forces deliberate wire-format decisions and avoids exposing implementation structure as the API. Gemini highlighted the concrete risk that returning a database object through tRPC can expose columns unintentionally; REST contracts make the external response shape explicit.
- Remaining tRPC case: Sol and Gemini still regard tRPC as viable for a genuinely controlled, TypeScript-only consumer base. Claude disagrees: even then, inferred router structure, package-version coupling, and weak versioning units remain public-contract liabilities. The panel has not resolved this because the actual consumer commitments are unknown.
- GraphQL boundary: Keep GraphQL out of the initial public surface. Reconsider it only after evidence such as independently versioned clients, repeated bespoke view endpoints or generic
include=logic, multi-request screens, or material payload/latency harm. Claude’s numerical triggers are proposed heuristics, not measured facts.
Disagreements
TypeScript-only public consumers: Sol and Gemini say a tightly controlled TypeScript-only audience makes tRPC substantially more competitive; Claude says a public API still warrants REST because inferred router structure and package coupling remain liabilities.
Meaning of tRPC’s public-API problem: Sol frames non-TypeScript interoperability as the likely migration trigger, while Claude argues language diversity is secondary and contract/versioning independence is the decisive issue.
Blind spots
Consumer commitment: No participant has evidence about the first year’s actual customers, SDK targets, webhook users, or required languages; that fact could materially change whether tRPC’s coupling is acceptable.
Workload shape: The product’s real relationship depth, number of independently upgraded clients, and data-heavy screens remain unspecified; measured query and payload pressure could justify GraphQL or reinforce REST.
GPT-5.6 Sol
The bar should be “close enough to tRPC in measured workflow,” not “identical DX.” Gemini’s “exact same developer experience” is too strong; Claude’s “tRPC-grade type safety” is defensible only if the contract layer eliminates duplicated types and CI verifies the generated public artifact.
Run a two-day vertical-slice benchmark
Implement the same 8–10 representative operations in:
- tRPC as the baseline.
- The leading OpenAPI-first candidate—prefer oRPC for RPC-like ergonomics or ts-rest for an explicitly HTTP-shaped contract.
Include:
- Simple CRUD
- Cursor-paginated list
- Nested read used by a real screen
- File upload
- Idempotent mutation
- Discriminated-union response
- Two typed domain errors
- Auth scopes
- Webhook payload
Use the actual frontend stack, validation library, CI, and monorepo—not a toy repository.
Acceptance requirements
Adopt the OpenAPI-first tool only if it passes all of these:
- Single definition: Request, response, and error schemas are authored once. No handwritten duplicate DTOs in handlers or the frontend.
- Compile-time propagation: Renaming or removing a response field makes every affected TypeScript call site fail compilation.
- Input safety: Invalid frontend inputs fail statically where representable; malformed network inputs are rejected at runtime.
- Output safety: A handler returning the wrong shape fails compilation or a mandatory contract test. Merely typing the handler with an unchecked cast does not count.
- Typed errors: The client can exhaustively distinguish domain errors such as
PLAN_LIMIT_REACHEDandVERSION_CONFLICT, rather than receiving onlyunknownor a generic exception. - External contract: The same definitions produce OpenAPI 3.1, and an independently generated Python or Go client can call the API without importing anything from the TypeScript repository.
- No drift: CI regenerates the spec and SDK, fails on an uncommitted diff, and performs a breaking-change check against the last released specification.
- Iteration-speed budget: Median warm edit → typecheck → usable frontend autocomplete time is no more than 20% slower than tRPC, with an absolute target under roughly** 10 seconds** on developer hardware.
- Reasonable ceremony: Adding a normal endpoint takes no more than about five extra minutes or 20% more changed lines than the tRPC version.
- Scale check: Repeat typechecking after generating or cloning enough contracts to approximate two years of growth—say 200–300 operations. Small-demo performance is not sufficient.
The decisive test is a breaking change:
Change
customer.name: stringtocustomer.displayName: string, add a new documented error variant, and alter one pagination field.
The tool passes if the server, internal frontend, generated SDK, OpenAPI diff check, and contract tests all identify the appropriate consequences without manually synchronizing types.
Where the other claims overreach
“Exact same developer experience” — no.
OpenAPI-first REST generally introduces schema annotations, generation, HTTP semantics, and sometimes stale generated artifacts. tRPC still has the lowest-friction refactoring loop when both sides share TypeScript. OpenAPI tooling has narrowed that gap substantially—modern generators produce ergonomic TypeScript clients—but it has not erased it toolchew.com.
“tRPC-grade type safety” — conditionally yes.
oRPC or ts-rest can provide equivalent safety for declared request and response shapes. That does not automatically guarantee implementation correctness, synchronized generated clients, exhaustive errors, or accurate OpenAPI output. Those require the acceptance gates above. oRPC is specifically positioned for TypeScript ergonomics plus native OpenAPI and typed contract errors tgmarinhopro.com.
“tRPC doesn’t work for non-TypeScript clients” — technically false, practically fair.
A non-TypeScript program can send HTTP requests to a tRPC endpoint. What it cannot consume natively is tRPC’s principal benefit: shared inferred types and its standard client integration. You could publish protocol documentation or generate an OpenAPI projection, but that makes interoperability an additional layer rather than the primary contract. In particular, @trpc/openapi is reported as alpha in tRPC v11.x and excludes subscriptions, which is a poor foundation for a production-critical public contract toolchew.com.
Validate the two untested assumptions
Do not merely assume future consumers are non-TypeScript. Make this a product requirement:
“A developer using Python, Go, or raw HTTP must be able to authenticate, discover operations, handle errors, and complete the quickstart without TypeScript packages or knowledge of our monorepo.”
If product leadership explicitly rejects that requirement and guarantees a TypeScript-only, tightly controlled consumer base, tRPC becomes much more competitive.
Also put one real data-heavy screen into the spike. If satisfying it requires five or more dependent requests, routinely transfers** more than twice the data used**, or drives repeated bespoke aggregation endpoints, GraphQL deserves a separate proof-of-concept. GraphQL should win through measured query-shape pressure—not hypothetical flexibility.
So the concrete decision rule is: choose the OpenAPI-first candidate if it catches the same representative breaking changes as tRPC, stays within 20% of tRPC’s iteration loop, and independently generates a working non-TypeScript client from the published contract.
Claude Opus 5
On the DX conflict: both of you are half right, and the disagreement is about which friction
Gemini is right about type fidelity. With ts-rest or oRPC there is no codegen step, no drift window, and no loss of inference: the Zod schema in the contract is the same object the client's return type is derived from. Anyone claiming REST costs you type accuracy is describing spec-first workflows (hand-written OpenAPI → openapi-typescript), not contract-first ones. On that axis, "exact same" is defensible.
Sol is right about friction, but misnames its source. The tax isn't weaker inference — it's that every procedure now requires HTTP decisions tRPC lets you skip: method, path shape, status code, where params live, and what a non-200 union looks like on the client. That's maybe 30 seconds and one small argument per endpoint. Real, cumulative, worth naming — not "less type-safe."
Two places tRPC genuinely still wins and REST cannot follow: non-JSON-serializable payloads (superjson-style Date/Map/BigInt transformers across the boundary — over HTTP you serialize and re-parse by hand) and multipart/streaming ergonomics. Neither of those is load-bearing for a SaaS CRUD API, which is why my answer doesn't move.
Two concessions
The GraphQL adoption figure: withdrawn. I can't trace it to a source I'd defend, so it shouldn't have been in the argument. It also wasn't doing any work — the case against GraphQL here is the operational cost of resolvers, query-cost limiting, and cacheless reads on a team of your size, which stands on its own.
"External consumers will be non-TypeScript" is an assumption, not a finding. Correct to flag it. But it's the weaker half of the argument, and removing it doesn't rescue tRPC — because tRPC's public-API problem isn't primarily language, it's that the contract is an inferred type of your implementation. To serve even a TypeScript-only public consumer, you publish AppRouter, which means:
- Your internal router structure becomes your public surface; renaming a procedure or restructuring a namespace is a breaking change for strangers.
- You have no versioning unit.
/v1/is cheap; "v1 of an inferred TypeScript type" is a published npm package you now maintain in parallel with the live server. - Consumers must match your TS version, Zod major, and client library — a support surface you don't control.
So a TS-only public API changes the reasoning but not the choice. What would actually change the choice: no public API at all, ever, and no webhooks, no Zapier/n8n-style integration, no agent tool-calling. If you can commit to that, tRPC is the better pick. You already said you can't.
The GraphQL threshold, concretely
Here are the lines I'd commit to in advance. These are decision heuristics I'm proposing, not measured industry data — but they're falsifiable, which is the point.
Trigger 1 — version skew across clients you can't deploy (the real one). Three or more independently-shipped clients where you do not control upgrade cadence — specifically native mobile apps, where a release from 18 months ago is still making requests. Coupled clients can be refactored alongside the server; uncoupled ones can't, so per-client response shaping turns into N versions × M endpoints forever. GraphQL's additive-only schema is precisely a version-skew tool. One web app you deploy with the server does not qualify, no matter how complex the UI.
Trigger 2 — you've accidentally reimplemented field selection. The tell is ?include=. One or two fixed expansions is fine. But when clients pass differing combinations, and you've written a generic include-resolver that walks relations, you now own resolvers, N+1, and depth limits with none of GraphQL's tooling. Migrate at that point — you're paying the cost already.
Trigger 3 — view-specific endpoint ratio above ~1:3. Count endpoints that exist to serve one screen (/dashboard-summary, /mobile-home-v2) versus resource endpoints. Past roughly one in four, you're maintaining a hand-rolled BFF and GraphQL is cheaper.
Trigger 4 — organizational, not technical. Three or more backend teams owning separate domains that a single client must compose in one round trip. That's Federation's actual use case. Below ~15–20 engineers it never applies; you don't have the domain boundaries yet.
Trigger 5 — measured payload economics. Over-fetch that breaches a real latency budget on constrained networks: p75 mobile, >2× payload bloat, and a product metric moving. Dashboard SaaS on broadband almost never clears this bar.
And a hard exclusion: GraphQL as your public surface only makes sense at Shopify/GitHub scale, where integrators build differentiated products on your data. The tell for what that costs is that both of them rate-limit by query cost points rather than request counts — you can't run a public GraphQL endpoint without a cost model, a complexity analyzer, and someone whose job it is to tune them.
What this means for your build order
The rule that keeps business logic out of HTTP handlers is what makes crossing a threshold cheap: if Trigger 1 or 2 fires in year two, you add GraphQL as an internal BFF over the same service layer and keep REST as the public contract. That's not two APIs in the sense I warned against — it's one domain layer with a second read-optimized transport for clients you own, added on evidence rather than anticipation.
Gemini 3.1 Pro
I concede to GPT-5.6 Sol and Claude Opus 5: typed REST is not exactly equal to tRPC in frictionless developer experience. You will write more boilerplate, and there is a distinct "contract tax" per endpoint.
However, paying this tax upfront is precisely what prevents accidental data leakage when the API goes public.
Why the "Contract Tax" Exists (and Why It Matters)
If we examine a representative endpoint—creating a new user and fetching their profile—the difference in plumbing becomes obvious:
- The tRPC approach (1 step): You define a
createUserprocedure, add a Zod input validator, and write the database logic. The frontend instantly infers the types from the return value. - The typed REST approach (2 steps): Using a library like
ts-rest, you must first define a standalone contract object (method: POST, path:/users, body schema, response schema). Only then do you implement the server logic to satisfy that contract.
Claude is right that this requires more per-endpoint plumbing. But tRPC's zero-friction inference is actually a liability for a future public API. When your implementation is your contract, returning db.user.findFirst() automatically exposes every database column to your frontend API client. Typed REST forces you to explicitly define the response schema in the contract step, decoupling your internal domain models from your external wire format before strangers ever see it.
Validating the Interoperability Assumption
The panel assumed your public consumers will use languages other than TypeScript. If your SaaS is a frontend developer tool (where every user lives in a Node/TypeScript ecosystem), exposing a public tRPC client is actually a viable strategy.
However, if your SaaS handles generic B2B logic, data processing, or integrations, assuming TypeScript-only consumers is dangerous. In 2026, AI agents and data science teams integrate via Python; enterprise backends integrate via Java, C#, or Go. Standard HTTP/REST guarantees they can interact with your system using standard libraries, rather than forcing them to reverse-engineer an RPC protocol.
The Missing Variable: Data Access Patterns
The panel unanimously favored REST without asking about your application's domain. The complexity of your data access patterns can easily overturn this recommendation in favor of GraphQL.
- When REST is correct: If your SaaS models discrete, action-oriented resources (e.g., creating a payment, sending a message, starting a server), REST is the optimal choice.
- When GraphQL wins: If your SaaS is a highly relational platform—like a headless CMS, a project management tool, or a BI dashboard—your frontend and your clients will need wildly varying trees of data.
If a single view needs to fetch a Project, its top 5 Tasks, the Assignees of those tasks, and the Assignees' availability statuses, REST will force you to either write highly specific compound endpoints or implement cascading N+1 network requests from the client. In these data-heavy, unpredictable domains, GraphQL's operational tax on the backend is cheaper than the performance tax imposed on your clients.