Prioritizing data in your query
The @defer
directive allows clients to prioritize part of a GraphQL query without having to make more requests to fetch the remaining information. You can use this directive to minimize the overhead when fetching data from Shopify. Rather than maintaining multiple queries and performing several API calls, clients can make a single request and receive the data as a stream of responses.
Requirements
Anchor link to section titled "Requirements"- Your app can make requests to the GraphQL Storefront API.
Choosing a supported client
Anchor link to section titled "Choosing a supported client"The @defer
directive is currently a draft contribution to the GraphQL specification. To maximize compatibility with clients that support some variant of the @defer
specification today, we have implemented the spec as of its description on August 23, 2022.
You can use one of the following compatible GraphQL libraries:
Optimize a query using @defer
Anchor link to section titled "Optimize a query using @defer"The @defer
directive can be applied to fragment spreads and inline fragments in a GraphQL query. Fields cannot use @defer
directly.
Many client libraries support @defer
in two ways: after each response is received, or once all responses have been received. To get the benefits of @defer
it’s strongly suggested to handle each response as it arrives, so the client can begin rendering as soon as possible.
The following example retrieves details about a product before the list of related products. It uses @defer
to deprioritize the productRecommendations
query, but still receive those recommendations afterward without making an additional request. Each response (including the undeferred part) begins with --graphql
.
In the provided example, the @defer
directive is used with the relatedProducts
fragment. This fragment, defined separately, includes the productRecommendations
query. By using @defer
on this fragment, we're instructing to the server that it's acceptable to return the data for productRecommendations
after the product.
When the server processes this query, it first returns the main product data, indicated by the "hasNext": true
in the response. The server then continues to process the deferred fragment and returns the product recommendations. You will know that all parts have been received when the response contains "hasNext": false
.
There might be some situations where Shopify believes it to be more efficient to serve the deferred fragment inline, rather than as a second streamed value. In this case, the initial response will contain all of the requested JSON. As before, streamed responses are complete when indicated by the presence of "hasNext": false
in the response.
Fetching carrier-calculated rates for the cart using @defer
Anchor link to section titled "Fetching carrier-calculated rates for the cart using @defer"As of 2024-07, Cart#deliveryGroups
supports a new withCarrierRates
argument, used to indicate intent to fetch carrier-calculated rates. This capability requires mandatory use of @defer
directive to ensure that the calculation of the delivery rates does not delay the cart response.
When fetching the delivery groups using withCarrierRates: true
inside a @defer
fragment, the cart will initially calculate (excluding the delivery rates) and resolve the response, and then stream the fragment containing the rates once they're available.
In the provided example, the first response fragment contains the non-deferred cart data, which is returned without delay from the pending carrier-calculated rates. Once the rates become available, the server returns the available delivery groups of the cart in the second fragment using the @defer protocol.
Technical details
Anchor link to section titled "Technical details"Streamed responses for @defer
follow the Incremental Delivery over HTTP specification for GraphQL. In particular, that means clients receive a multipart content response, indicated by the HTTP header of content-type: multipart/mixed; boundary=graphql
. If the client only supports a maximum of HTTP/1.1
, the response will also be served using transfer-encoding: chunked
, which is no longer necessary as of HTTP/2
.