DataLoader helps to group many small data requests into fewer big ones and remembers past requests to avoid asking the same thing twice.
DataLoader batching and caching in GraphQL
Start learning this pattern below
Jump into concepts and practice - no test required
const DataLoader = require('dataloader'); const loader = new DataLoader(async (keys) => { // keys is an array of IDs // Return an array of results in the same order }); // Use loader.load(key) to get data for one key // Use loader.loadMany([key1, key2]) to get data for many keys
The function passed to DataLoader receives an array of keys and must return a Promise of an array of results in the same order.
DataLoader caches results during one request to avoid duplicate fetching.
const userLoader = new DataLoader(async (userIds) => { const users = await db.getUsersByIds(userIds); return userIds.map(id => users.find(user => user.id === id)); });
const postLoader = new DataLoader(async (postIds) => { const posts = await db.getPostsByIds(postIds); return postIds.map(id => posts.find(post => post.id === id)); });
This program creates a DataLoader to batch user ID requests. It fetches users with IDs 1, 2, and 3 efficiently and prints their data.
const DataLoader = require('dataloader'); // Fake database function async function getUsersByIds(ids) { const allUsers = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]; // Simulate async DB call return new Promise(resolve => { setTimeout(() => { resolve(allUsers.filter(user => ids.includes(user.id))); }, 100); }); } // Create DataLoader instance const userLoader = new DataLoader(async (userIds) => { const users = await getUsersByIds(userIds); return userIds.map(id => users.find(user => user.id === id)); }); // Use DataLoader to load users async function main() { const user1 = await userLoader.load(1); const user2 = await userLoader.load(2); const user3 = await userLoader.load(3); console.log(user1); console.log(user2); console.log(user3); } main();
DataLoader batches requests that happen in the same tick of the event loop.
Cache is per DataLoader instance and usually per request to avoid stale data.
Always return results in the same order as the keys array to avoid mismatches.
DataLoader groups many small data requests into fewer big ones to improve speed.
It remembers past requests during one operation to avoid asking the same data twice.
Use it in GraphQL servers to efficiently load related data like users or posts.
Practice
DataLoader in a GraphQL server?Solution
Step 1: Understand DataLoader's role in GraphQL
DataLoader groups many small data requests into fewer big ones to reduce database calls.Step 2: Identify caching behavior
It also caches results during one operation to avoid duplicate requests for the same data.Final Answer:
To batch multiple data requests into a single request and cache results during one operation -> Option AQuick Check:
Batching + caching = To batch multiple data requests into a single request and cache results during one operation [OK]
- Thinking DataLoader replaces the database
- Confusing DataLoader with schema generation tools
- Assuming it handles authentication
Solution
Step 1: Recall DataLoader instantiation syntax
DataLoader is a class and must be instantiated with thenewkeyword.Step 2: Check method usage
The constructor takes a batch loading function as argument, sonew DataLoader(batchLoadFn)is correct.Final Answer:
const loader = new DataLoader(batchLoadFn); -> Option BQuick Check:
Usenewwith DataLoader class [OK]
- Omitting 'new' keyword
- Using incorrect method calls like .new or .load
- Calling DataLoader as a function without 'new'
const DataLoader = require('dataloader');
const batchLoadFn = async keys => keys.map(key => key * 2);
const loader = new DataLoader(batchLoadFn);
(async () => {
const result1 = await loader.load(2);
const result2 = await loader.load(3);
console.log([result1, result2]);
})();Solution
Step 1: Understand batchLoadFn behavior
The batch function doubles each key: for key 2 returns 4, for key 3 returns 6.Step 2: Analyze loader.load calls
Callingloader.load(2)andloader.load(3)triggers batchLoadFn with keys [2,3], returning [4,6].Final Answer:
[4, 6] -> Option AQuick Check:
Keys doubled = [4, 6] [OK]
- Expecting original keys as output
- Confusing async behavior with undefined
- Ignoring batch function logic
const DataLoader = require('dataloader');
const batchLoadFn = async keys => {
return keys.map(key => fetchUserFromDB(key));
};
const loader = new DataLoader(batchLoadFn);
loader.load(1).then(user => console.log(user));
Assuming fetchUserFromDB returns a Promise resolving to user data.Solution
Step 1: Check batchLoadFn return type
batchLoadFn returns an array of Promises because fetchUserFromDB returns a Promise for each key.Step 2: Understand DataLoader batch function requirement
DataLoader expects batchLoadFn to return a single Promise resolving to an array of results, not an array of Promises.Final Answer:
batchLoadFn should return a Promise resolving to an array, but it returns an array of Promises -> Option DQuick Check:
Return a Promise of array, not array of Promises [OK]
- Returning array of Promises instead of Promise of array
- Misusing 'new' keyword with DataLoader
- Passing single key instead of array to batch function
Solution
Step 1: Understand DataLoader lifecycle
DataLoader instances should be created per request to cache data only during that request and avoid stale data.Step 2: Use DataLoader to batch and cache IDs
Usingloadfor each user or post ID lets DataLoader batch requests and cache results within the request.Final Answer:
Create one DataLoader instance per request for users and posts, and useloadfor each user or post ID -> Option CQuick Check:
Per-request DataLoader + load calls = Create one DataLoader instance per request for users and posts, and useloadfor each user or post ID [OK]
- Sharing DataLoader globally causing stale cache
- Creating new DataLoader per field causing no batching
- Skipping DataLoader and querying DB repeatedly
