7. Using @defer
3m

Overview

With GraphQL s, some s may take slower to resolve than others. From a user perspective, this could mean staring at a loading screen for longer than they want to.

The Apollo has a built-in feature up its sleeve to help us out with this issue! In this lesson, we will:

  • Learn about the @defer directive
  • Apply the @defer directive to a slow field in our query

Investigating a slow query

Let's take this example of an regularly sent to the Poetic Plates API. The GetRecipePage includes details about a specific recipe, its ingredients and instructions. It also asks for a list of recently added recipes.

query GetRecipePage {
recipe(id: "recOZrH0RhjSjATBp") {
id
name
cookingTime
prepTime
readyTime
servings
instructions
ingredients {
text
}
}
recentlyAddedRecipes {
name
cookingTime
servings
}
}

When we try running this using Studio Explorer, we can see for ourselves just how long this query takes 🐢

From the client app, the important information is located in the recipe details. That's what the users want to see right away! Unfortunately, the recentlyAddedRecipes is slowing everything down. @defer to the rescue!

The @defer directive

The @defer enables our queries to receive data for specific s incrementally, instead of receiving all data at the same time. This is helpful whenever some s in a query take much longer to resolve than others, like the recentlyAddedRecipes and its subs.

We can only defer certain s in our , specifically:

  • Root fields of the Query type (along with their subfields)
  • Fields of any entity type (along with their subfields)

Since recentlyAddedRecipes is a root in our Query type, it matches the first situation and we can safely defer it!

Note: Curious about entity types? Check out our Odyssey Voyage series.

How to use @defer

To use the @defer , we apply it to fragments in our queries.

So the GetRecipePage with the recentlyAddedRecipes deferred would look like this:

query GetRecipePage {
recipe(id: "recOZrH0RhjSjATBp") {
id
name
cookingTime
prepTime
readyTime
servings
instructions
ingredients {
text
}
}
... @defer {
recentlyAddedRecipes {
name
cookingTime
servings
}
}
}

There's an even easier way to do this in , so you don't have to remember the syntax every time.

With the open, we can place our cursor on the we want to defer, right-click and select "Wrap with inline @defer " (or "Extract @defer ") and automatically takes care of the syntax for us.

https://studio.apollographql.com

Explorer with defer options

Let's run the query now.

We can see in the Response panel that a new section called "Response Timeline" has appeared at the bottom.

https://studio.apollographql.com

Explorer with response timline after defer

When we hover over the first circle, we can see the data about our recipe is returned, but not the recentlyAddedRecipes .

When we hover over the second circle, we can see the additional data for the recentlyAddedRecipes returned, a few milliseconds afterwards.

Amazing! This is going to make a big difference in our client app experiences.

Note: Clients must support receiving deferred query responses as multipart HTTP responses. This functionality is currently supported in Apollo Client for Web and Kotlin (experimental).

Practice

Use the below to answer the follow question:

type Query {
availableFruits: [Fruit]
fruit(id: ID): Fruit
randomFruit: Fruit
}
type Mutation {
buyFruit(fruitId: ID): Fruit
}
type Fruit {
id: ID
cost: Float
isInSeason: Boolean
color: String
}
Which of the following fields (and its subfields) can be deferred?
Which of the following statements are true?

Key takeaways

  • The @defer directive enables our queries to receive data for specific fields incrementally. We apply it to a fragment in our query.
  • Apollo Router comes with built-in support for the @defer directive.

Conclusion

And there we have it: Poetic Plates is a ready to receive queries and share the magic of poetic AI-generated recipes!

Awesome job! We've learned what the is and the components that make it work: subgraphs and a . We created a with an existing GraphQL API and now it's set up for success inside . We've got a public variant ready to receive queries for API consumers to try out. We've got access to and metrics segmented by clients and we can use @defer to improve our user experience.

This is only the beginning, we've still got a lot to learn about and the . If you want to learn how to make changes to your safely and confidently, the next course, "GraphOS: Shipping your supergraph" is for you! See you there! 👋

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.