ShopifyLeanne ShaptonProblem & solution
Solving the N+1 Problem for GraphQL through Batching
Summary
GraphQL avoids REST’s over-fetching and under-fetching by letting clients request specific fields, but its field-specific resolvers can create the n+1 problem for nested data. With N authors, a server may make one datastore round trip for authors and N more for addresses, rather than loading all addresses in one additional trip. Shopify’s GraphQL Batch Ruby library addresses this through promises and batch loaders: resolvers request data without resolving immediately, similar loads are grouped, and the loaders fulfill them together. During execution, grouped promises are loaded and replaced with results, while nested fields can enter later batching rounds. The approach reduces datastore queries and computing power for the same requests, became general best practice at Shopify, and was released as open-source.
Context
Shopify uses GraphQL for its Storefront API, where clients can request precise fields through a schema and field-specific resolvers. The post focuses on the n+1 problem: nested GraphQL data can cause many unnecessary datastore round trips, with request costs harder to predict than in REST.
Approach / What changed
GraphQL Batch for the GraphQL Ruby library lets resolvers return promises instead of immediately resolved values. Batch loaders group similar data requests, load them together, and replace the promises with results; nested field resolution can create additional grouped loads in later execution rounds.
Takeaways
For N authors and their addresses, naive field resolution can require one datastore trip for authors plus N trips for addresses; batching can reduce this to two trips.
GraphQL Batch uses promises to delay field resolution and batch loaders to group similar loads before fetching their results.
Shopify reported reduced computing power for the same requests, adopted GraphQL Batch as general best practice, and open-sourced the library.
FAQ
How does GraphQL Batch reduce n+1 datastore requests?
Resolvers return promises rather than resolving each field immediately. GraphQL Batch groups similar loads and uses a batch loader to fetch them together, replacing the promises with the loaded results.
Can batching handle nested GraphQL fields?
Yes. After an object field loads, its nested fields resolve through their own resolvers. Loads from those resolvers can be grouped with similar requests that have not yet executed.
Why is the n+1 problem harder to predict in GraphQL than in REST?
REST costs are more predictable because requests generally involve one trip per endpoint. GraphQL uses one endpoint, but a query can request nested data whose resolver and datastore costs are not apparent until execution.
Source and freshness
- Source
- shopify.engineering
- Published
- Added to Yomu
Summaries are generated from the original by a language model. Check the original before relying on it.
Keep reading
Related reading
The Good Stuff
Paid picks we use ourselves. Links carry a referral code — a subscription through one earns us a commission at no extra cost to you.
The best engineering reads, once a week
One useful email. Unsubscribe anytime.