How DataFetcher and DataLoader Work
Fast recall
Quick revision
Core answer
Assesses depth of GraphQL internals understanding.
Candidates who only know annotations but not the underlying DataFetcher mechanism will struggle with performance tuning.
Candidates who only know annotations but not the underlying DataFetcher mechanism will struggle with performance tuning.
Interview-ready guide
Interview answer
DataFetcher is the resolver primitive in graphql-java — every single field in your schema has one, whether you wrote it explicitly or Spring registered it through @QueryMapping. For simple scalar fields like title, the default PropertyDataFetcher calls the getter. For relational fields like Book.author, you provide a custom fetcher.
The N+1 performance trap:
- The performance trap shows up on list queries: if you fetch fifty books and each book's
authorfield fires its own database call, you get fifty-one total queries — one for books, fifty for authors - Each resolver runs independently with no awareness of the other pending loads at the same level — this is by design, and DataLoader is the intended fix
How DataLoader solves it:
- Instead of hitting the database immediately, each resolver calls
authorLoader.load(id)and gets back aCompletableFuture; the engine collects all load calls during one execution level, then dispatches them as a single batch — oneWHERE id IN (...)replaces fifty singleton selects - The engine's level-by-level execution creates the batching window: all DataFetchers at one depth complete before the next depth dispatches, which is why DataLoader can collect keys across siblings
The non-negotiable ordering rule:
- Your batch function must return results in the same order as the input key list — DataLoader matches results to parents by position, not by key lookup
- If you return them in database sort order instead, data silently attaches to the wrong parent objects — it looks like corruption but it's an ordering bug
Per-request caching:
- DataLoader caches within the request — two books sharing the same author ID produce one lookup; but if a mutation updates that author mid-request, call
loader.clear(id)explicitly to prevent stale data
I recommend wiring DataLoader for every @SchemaMapping that resolves a related entity from the start — retrofitting is significantly harder after the N+1 problem is discovered in production.
How DataFetcher and DataLoader Work
Direct Answer
A DataFetcher is the low-level resolver interface in GraphQL-java — every field in the schema is backed by one. DataLoader is a batching and caching utility that groups multiple individual loads into a single bulk call, solving the N+1 problem by deferring resolution until all fetchers in the current execution level have registered their keys.
Common Mistakes & Pitfalls
Candidates who only know annotations but not the underlying DataFetcher mechanism will struggle with performance tuning.
Check your understanding
Answer these without looking back at the article.
- What happens if the batch loader returns results in the wrong order?
- How do you disable per-request caching in DataLoader, and when would you want to?
- How does DataLoader interact with async execution in graphql-java?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.