Resolvers and the N+1 problem

GraphQL Course · lesson 4 of 14 · 6 min read

GraphQL makes N+1 easier to cause than REST did - and DataLoader is the standard fix.

Open this lesson in the learning hub

Key points

  • Each field has a resolver: a function returning that field’s value.
  • A nested field resolves once per parent object, which is where N+1 appears.
  • Ask for 50 orders each with a customer, and a naive resolver runs 1 + 50 queries.
  • The client cannot see this - one innocent-looking query can hammer your database.
  • DataLoader batches the per-item calls within one tick and caches within the request.

Example

// Naive: one query per order
@SchemaMapping(typeName = "Order")
public Customer customer(Order order) {
    return repo.findById(order.customerId());   // N times
}

// Batched: one query for all of them
@BatchMapping(typeName = "Order")
public Map<Order, Customer> customer(List<Order> orders) {
    var ids = orders.stream().map(Order::customerId).toList();
    var byId = repo.findAllById(ids).stream()
        .collect(toMap(Customer::id, c -> c));
    return orders.stream()
        .collect(toMap(o -> o, o -> byId.get(o.customerId())));
}

Nested resolvers run per parent - assume N+1 by default and batch before you ship.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the GraphQL Course course, and every lesson in it is listed on the GraphQL Course contents page.