Home/Labs/DataLoader N+1 Batcher
All 280 Labs
INTERACTIVE LAB🗄️

GraphQL N+1 & DataLoader Lab (Interactive)

Execute a nested feed query and watch 1+N resolver SQL collapse into batched IN-queries at the microtask tick. Scale the requested post count, nest comment authors for explosive fan-out, and toggle DataLoader plus per-request scoping to see query counts, latency, and leak risk.

GraphQL N+1 & DataLoader Batching

Execute { posts { author comments { author } } } and watch resolver-per-field fan-out collapse into event-loop-tick batches.

SQL traffic (idle)

Press "Execute query" to trace resolver SQL.

DB round-trips

281 naive

Latency

—

Pool acquires

—

Keys deduped

—

Each field gets its own resolver; the engine walks the AST top-down, so 40 posts each fire a Post.author lookup — 281 statements for one HTTP request.

40 posts share just 23 distinct authors: DataLoader queues .load(id) promises until the microtask tick ends, dedupes to one WHERE id = ANY(...), and the batch fn must return results in the exact key order.

How It Works Under the Hood

GraphQL assigns every field its own resolver, so posts(limit:100){author} runs one query for the list then one per post — 101 statements, or 1,101 with comments and comment authors — starving connection pools. Lee Byron’s DataLoader queues each loader.load(id) promise until the Node event-loop tick ends, dedupes repeated keys, and flushes them into a single WHERE id = ANY(...) batch, resolving each promise from the matching row. Batch functions must return results in exact key order, and loaders must be built per request or one user’s cached rows leak into another’s response.

Core Architectural Principles

  • Per-field resolvers multiply one HTTP request into 1 + N + N×M database round-trips.
  • DataLoader batches keys at the microtask tick into one IN-query and memoizes repeated ids.
  • Loaders instantiated per request context; global singletons cause cross-user leaks and stale RAM.
Interview Round Script

When asked how to make GraphQL fast, explain the mechanism, not the buzzword: resolvers queue load(id) calls, the tick boundary flushes a single batched query, 101 statements become 2, and the batch fn must preserve array ordering. Then volunteer the per-request scoping rule — security and staleness — because that is what distinguishes production experience from tutorial knowledge.

Key Trade-Offs

Batching crushes query volume 90-99% but adds loader plumbing per entity and strict key-order contracts.

Related Curriculum Chapter

The GraphQL N+1 Problem & DataLoader Solution

Read Full Chapter Blueprint

Explore More Interactive Labs

View All 280 Labs