Learning on Web Dev Open is free for all.

System Design & Performance > Where the milliseconds goN+1, in three places at once
Phase 06Where the milliseconds go300 of 434

N+1, in three places at once

The same shape in your ORM, in your API calls and in your component tree. Learn to see it once and you see it everywhere.

Concept14 minAI adversary

One query for the list, then one query per row for its author. Twenty rows, twenty-one queries, each with its own round trip. It is invisible locally where the database is on the same machine and the list has three rows, and it is a four-second endpoint in production where the database is a millisecond away and the list has two hundred. The version with an ORM hides it best, because the extra queries are triggered by a property access that looks free.

The same shape appears at the API layer, a client that fetches a list and then a detail per item, and in the render tree, where each card independently calls a hook that fetches. GraphQL is particularly good at producing it by design, which is why dataloader-style batching is not an optimisation there but part of the base implementation.

Two fixes, and choosing between them is the design work. Batch: collect the ids and issue one query or one request for all of them, which keeps the code shape and adds a coordination layer. Or restructure: fetch the joined data once at the top and pass it down, which is simpler and couples the component to its parent. Neither is always right, but doing neither is always wrong.

You should now be able to

  • Recognise the N+1 pattern in database, network and render code
  • Fix it by batching or by changing the query, deliberately
  • Explain why it never shows up in development
Ask the community

Loading…