From REST to GraphQL: When the Migration is Actually Worth It
Migrated 4 client APIs from REST to GraphQL and back from 2 of them. Here's when GraphQL pays off and when REST is still the right answer in 2026.
The honest summary
I've migrated four production APIs from REST to GraphQL over the last two years. I've migrated two of them back. The other two are still GraphQL and serving real users.
The pattern: GraphQL is genuinely better for some use cases and genuinely worse for others. The discourse online overstates both sides.
Here's the framework I use to decide, with the two migrations I regretted as concrete examples.
When GraphQL is worth it
Client-driven data needs
If your frontend regularly needs different shapes of the same data (mobile shows compact list, web shows expanded cards, dashboard needs aggregates), REST forces you to either over-fetch (large payloads) or proliferate endpoints (/users, /users-summary, /users-with-orders, etc.).
GraphQL lets the client ask for exactly what it needs in one query. Bandwidth drops, endpoint count stops growing.
This is the strongest case for GraphQL and the one I see win in production.
Multiple consumers with different needs
iOS, Android, web, and a third-party integration partner all consume your API. REST means versioning hell — change the API, break a consumer. GraphQL means each consumer queries what they need, schema changes are mostly additive.
Strongly typed frontend code
GraphQL Code Generator (or Apollo's tooling) gives you TypeScript types for every query result automatically. Your React components are fully typed end-to-end, no manual type definitions. This is a real DX win on TypeScript codebases.
Relationship-heavy data fetching
If your screens regularly need "user to orders to line items to product to category" (5 hops), REST means 5 round-trips or one custom endpoint. GraphQL resolves it in one query with a server-side join strategy.
When REST is still right
Public APIs with documentation requirements
REST plus OpenAPI spec is the standard for public APIs that third parties consume. Stripe, Twilio, GitHub — all REST. The tooling, mental model, and documentation ecosystem are unmatched.
Simple CRUD APIs
If your API is "list X, create X, update X, delete X" for half a dozen resources, GraphQL adds ceremony without value. REST is faster to write and faster to reason about.
Caching at the HTTP layer
REST GET requests are trivially CDN-cacheable. Add Cache-Control headers, point Cloudflare at the origin, done. GraphQL caching is possible (persisted queries plus GET) but harder to set up and maintain.
Teams without GraphQL fluency
GraphQL has a real learning curve — resolvers, DataLoader for N+1 prevention, schema design, error handling conventions. A team that hasn't shipped GraphQL before will move slower for the first 6 months.
File uploads, streaming, webhooks
GraphQL handles these awkwardly. File uploads need multipart extensions, streaming needs subscriptions or SSE, webhooks are flat-out REST. If your API is heavy on these, REST is the right answer.
The two migrations I regretted
Regret 1: B2B SaaS with simple CRUD
Migrated a B2B SaaS API from REST to GraphQL because "modern stack." The data model was 8 resources with simple CRUD. Frontend was one web app.
Six months later, the team had an Apollo Server with ~200 lines of resolver boilerplate, custom DataLoader instances for every relationship, a frontend that was no faster than the REST version, and two engineers complaining the GraphQL setup was "more annoying than helpful."
Migrated back to REST in three weeks. Codebase shrunk 30 percent. Velocity went up.
Lesson: GraphQL's win is in heterogeneous consumer needs. If you have one frontend and simple CRUD, REST is faster.
Regret 2: Public API with rate limiting
Built a Web3 indexer API in GraphQL. Customers integrated against it.
Problem: rate limiting GraphQL is hard. A single query can fetch a list of 1000 items with 5 nested fields each. A REST GET items with limit=10 is naturally constrained. GraphQL queries can request arbitrary depth and breadth.
We ended up implementing query complexity analysis (depth limits, field limits, custom cost scoring). Worked, but took 3 weeks and adds maintenance burden.
Lesson: Public APIs are easier to safely rate-limit when they're REST.
The hybrid pattern
A pattern I now use on most projects: REST for the API surface, GraphQL for one specific use case where it shines.
Example: a SaaS dashboard's "build a custom widget" feature needs flexible queries. The widget builder talks GraphQL to a specific endpoint. The rest of the app uses REST.
You get the best of both: REST simplicity for normal CRUD, GraphQL flexibility where you need it.
My default in 2026
TL;DR
If you're evaluating REST vs GraphQL for a project and want a second opinion before committing, contact me.
You might also like
Building a Production REST API with Node.js and Express in 2026
Layered architecture, validation, error handling, auth, rate limiting, observability — the patterns I use to ship Node.js + Express APIs that don't fall over in production.
Background Jobs in Node.js 2026: BullMQ, Trigger.dev, or Inngest?
Compared on real client projects: BullMQ vs Trigger.dev vs Inngest for Node.js background jobs. What I pick for what, with cost, DX, and operational trade-offs.
Building Production AI Agents with Claude 4.7 and Tool Use
What I learned shipping AI agents to production: tool design, prompt structure, durable execution, observability, and cost control. Practical patterns from real client work.