concept

GraphQL N+1 Problem

also called DataLoader Pattern

The query explosion that occurs when each item in a list independently resolves its nested fields, turning one request into hundreds of database calls.

graphqlperformanceapi

GraphQL's resolver model is per-field, which is what makes it composable and what creates this problem. A query for 100 orders, each with its customer, executes one query for the orders and then one per order for the customer — 101 queries where a joined SQL statement would have been one.

It is not a flaw so much as a consequence that must be actively managed, and the standard remedy is batching with a loader: instead of fetching immediately, each resolver registers a key, the batches are collected within a tick of the event loop, and a single query fetches all of them. Requests within one operation are also deduplicated, so the same customer referenced by twenty orders is fetched once.

The other half of the problem is that GraphQL lets clients compose queries the server did not anticipate, so a deeply nested query can be arbitrarily expensive. The controls are query depth limits, complexity scoring with a per-request budget, and persisted queries — where clients register their operations ahead of time and send an identifier, so only known and reviewed queries can run. Persisted queries are the strongest control and also remove the payload and parsing cost; they are the right default for first-party clients.

The architectural read: GraphQL moves query planning from the server to the client, which is its benefit and its risk, and the controls above are what make that trade safe in production.