1. The N+1 problem
3m

Overview

As developers, we aim to build performant applications that scale with our users and data, without sacrificing development speed. help us move fast by reusing existing APIs within our reach. Working within our , we define requests to data sources and map their responses to our types and .

But sometimes, even with clean code and good intentions, performance issues can sneak in unnoticed!

In this course, we'll shine a spotlight on one of those sneaky performance bottlenecks: the N+1 problem. This issue isn't exclusive to or Connectors! It can show up in other data-fetching scenarios, whether we're calling REST API endpoints or running database queries.

In this lesson, we'll learn what the N+1 problem is, how it impacts performance, and how batching solves it.

One request leads to N more

Here's what we mean by the N+1 problem. We start with an initial request (the 1 in the N+1 equation) that then triggers multiple follow-up requests (the N). We don't know the number of follow-up requests, N, until the first request is executed.

Requests from the client to REST APIs

Let's consider a storefront page that displays a list of orders, where each order includes details about the customer who submitted it.

For an application using REST APIs, the client would need to:

  1. Send one request to fetch the most recent list of orders, which could include anywhere from 1 to 10 orders.
  2. When the response arrives, the client now has up to 10 unique userId values. This is the N number of follow-up requests.
  3. The client sends 10 additional requests—one for each userId—to fetch the corresponding customer data.
  4. After receiving these 10 responses, the client stitches the data together for display.

Visual diagram of the client process for retrieving a list of orders and each user

That's 11 total network requests to load a single page!

As the number of orders increases, so does the number of user data requests. This is the N+1 problem in action. While a few extra requests might seem manageable, this pattern can lead to significant performance slowdowns as queries scale—resulting in higher costs and slower user experiences.

All of those steps that the client needs to do? That's . Orchestrating API calls efficiently is a constant challenge in app development; we typically handle it by writing a lot of procedural code. With the declarative approach of , we can speed up that process.

Requests from the client with the help of GraphQL & Apollo Connectors

Let's take the same example with the storefront page displaying the most recent orders. This time, we'll use , where the might look something like this:

query GetRecentOrders {
recentOrders {
id
status
submittedAt
user {
name
location
}
}
}

To retrieve that data, the client would need to send just one request containing the above. No need to wait for the response, make follow-up requests, and stitch all that data together. Everything is handled smoothly (and much more quickly!) on the server side.

With the approach, we've shifted the responsibility of the data fetching logic over to the server. This is all defined declaratively in the schema using . But it doesn't automatically solve the N+1 problem for us. We need to make sure our Connectors are set up correctly to enable batching.

Batching to the rescue

To solve the N+1 problem, we use batching: a technique that combines many similar requests into a single request.

Instead of fetching users one ID at a time, batching lets us ask for all the users we need information about, all in one go.

Visual diagram of the client process for retrieving a list of orders and each user, with batching

If you've worked with before, then you'll recognize batching as the job of a data loader. You'd create a data loader class, implement the loading method, then update the function to use the data loader.

With , it's simpler: we keep our work in the schema and use a called $batch combined with a REST API batch endpoint. We'll explore this in more detail later on in the course.

Learner pre-requisites

We assume that you're familiar with the basics of a and how to send GraphQL . Check out graphql.com/learn if you need a refresher. You don't need to know any particular programming language for this course.

It would also be helpful to be familiar with the basics of . Check out "GraphQL meets REST, with Apollo Connectors" for an overview.

Practice

Which of the following avoids the N+1 problem?
True or False: The N+1 problem is exclusive to GraphQL and doesn't affect other types of APIs.

Key takeaways

  • The N+1 problem is a performance issue where one request leads to N additional and often unexpected requests, resulting in slow response times.
  • Batching is the solution to the N+1 problem: replacing multiple requests by combining them into a single batched request.

Up next

Hands on the keyboard time! Next up, we'll get our project set up so we can see N+1 and batching in Connectors in action.

Next

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.