DataLoader helps reduce repeated database calls by batching and caching requests. It makes your NestJS app faster and more efficient.
DataLoader integration in NestJS
import DataLoader from 'dataloader'; const loader = new DataLoader(async (keys) => { // batch load function returns results in order of keys const results = await batchFetchFromDatabase(keys); return keys.map(key => results.find(r => r.id === key)); });
The batch load function receives an array of keys and must return results in the same order.
DataLoader caches results during a request to avoid duplicate fetches.
const userLoader = new DataLoader(async (userIds) => { const users = await userService.findByIds(userIds); return userIds.map(id => users.find(user => user.id === id)); });
const postLoader = new DataLoader(async (postIds) => { const posts = await postService.findByIds(postIds); return postIds.map(id => posts.find(post => post.id === id)); });
This example shows a NestJS service using DataLoader to batch user ID requests. It caches during one request scope and returns user names in order.
import { Injectable, Scope } from '@nestjs/common'; import DataLoader from 'dataloader'; interface User { id: number; name: string; } @Injectable({ scope: Scope.REQUEST }) export class UserLoader { public readonly loader: DataLoader<number, User>; constructor(private readonly userService: UserService) { this.loader = new DataLoader(async (userIds: readonly number[]) => { const users = await this.userService.findByIds(userIds as number[]); return userIds.map(id => users.find(user => user.id === id)); }); } } // Usage in resolver or service async function getUserNames(userLoader: UserLoader, ids: number[]) { const users = await Promise.all(ids.map(id => userLoader.loader.load(id))); return users.map(user => user?.name ?? 'Unknown'); } // Mock UserService for demonstration class UserService { private users = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Carol' }, ]; async findByIds(ids: number[]): Promise<User[]> { // Simulate async DB call return this.users.filter(user => ids.includes(user.id)); } } // Demo run (async () => { const userService = new UserService(); const userLoader = new UserLoader(userService); const names = await getUserNames(userLoader, [1, 2, 3]); console.log(names.join(', ')); })();
Use request-scoped providers in NestJS to create a new DataLoader instance per request.
Always return results in the same order as the keys array to avoid mismatches.
DataLoader caches only during one request; it does not cache across requests.
DataLoader batches and caches data fetching to improve performance.
Use it in NestJS with request-scoped providers for safe caching.
Always keep the batch function output order matching the input keys.