Solving the GraphQL N+1 Problem with DataLoader

A
Author
30 May, 2026 1 min read 373 views

Fetch 50 books with their authors, and a naive server runs 1 query for the books plus 50 queries for authors. That's the N+1 problem, and it's the most common GraphQL performance issue.

Why it happens

Book: {
  // called once per book, each with its own query
  author: (book, _, { db }) => db.query('SELECT * FROM authors WHERE id = $1', [book.authorId]),
}

DataLoader batches the calls

DataLoader collects every load(id) call made in the same tick, then calls your batch function once with all the ids.

import DataLoader from 'dataloader';

function createLoaders(db) {
  return {
    authorById: new DataLoader(async (ids) => {
      const { rows } = await db.query('SELECT * FROM authors WHERE id = ANY($1)', [ids]);
      const byId = new Map(rows.map((a) => [String(a.id), a]));
      return ids.map((id) => byId.get(String(id)) ?? null); // same order as ids!
    }),
  };
}

Create loaders per request

context: async ({ req }) => ({
  db,
  user: await userFromToken(req.headers.authorization),
  loaders: createLoaders(db), // fresh cache per request, so users never see each other's data
}),
Book: {
  author: (book, _, { loaders }) => loaders.authorById.load(book.authorId),
}

Now 50 books need just 2 queries: one for books, one for all their authors.

The two rules of batch functions

  1. Return an array the same length as the keys.
  2. In the same order as the keys (use null or an Error for missing items).

One-to-many relations

booksByAuthor: new DataLoader(async (authorIds) => {
  const { rows } = await db.query('SELECT * FROM books WHERE author_id = ANY($1)', [authorIds]);
  return authorIds.map((id) => rows.filter((b) => String(b.author_id) === String(id)));
}),

Log the number of SQL queries per GraphQL request in development so N+1 regressions are caught early.

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.