DataLoader is the standard fix for GraphQL's N+1 query problem. Batch your database calls per request, cache within the request lifecycle, done.
But once DataLoader is in production, you're flying blind. Which loaders are actually called per request? Is your cache hit rate 15% or 60%? Should your batch size be 10 or 50? APM tools tell you resolver latency, but they don't understand DataLoader batching.
I built .
The problem: invisible batching
Open Collective runs one of the largest open-source GraphQL APIs on the web. Their server/graphql/loaders/ directory contains 96 DataLoader instances across 20 files — loaders for collectives, expenses, transactions, members, comments, orders, and more.
Without instrumentation, none of these questions are answerable:
Which loaders fire per request? You can guess from the schema, but you don't know for sure without tracing.
Are batches efficient? A loader called 20 times in a request should ideally create 1 batch of 20 — not 20 batches of 1.
What's the cache hit rate? DataLoader's cache is per-request, but hit rate varies wildly depending on query shape.
Is the batch size right? Too small = more round trips. Too big = slow batches. The default is often wrong.
The tool: dataloader-ai
and replaced 95 of 96 DataLoader instances with DataLoaderAI, adding a descriptive name to each:
// before
new DataLoader(async (ids) => { ... })
// after
new DataLoaderAI(async (ids: readonly number[]) => { ... }, { name: 'collective-by-id' })
The changes were mechanical — 20 files, 397 insertions, 379 deletions. You can see the full — an Apollo Server with 5 DataLoaderAI loaders (users, products, categories, reviews, orders) and a load-test script that fires 5 different query patterns.
Run it:
git clone https://github.com/currentlybuffering/dataloader-ai
cd dataloader-ai/src/examples/realistic-ecommerce
npm install
node index.ts
# in another terminal:
node load-test.ts
The terminal report shows all 5 loaders with live metrics. The orders loader (15-35ms simulated DB latency) consistently gets "increase batch size" recommendations. The category loader (3-7ms) holds steady. The reviews loader shows the most cache-hit variance because review queries overlap differently per request pattern.
What this means for your GraphQL server
If you're running DataLoader in production:
Add names to your loaders. Even if you don't use dataloader-ai, naming your loaders makes debugging dramatically easier. Just add a
nameproperty to your DataLoader options.Check your batch efficiency. Are you getting 1 batch of N keys, or N batches of 1 key? If resolvers call
.load()late in the cycle (after awaits), DataLoader can't batch them.Measure cache hit rate per query. A query that fetches the same user 5 times in one request should have 80% cache hit rate on the user loader. If it's 0%, something is wrong with your per-request cache lifecycle.
Tune batch sizes to your actual latency. The default
maxBatchSizein DataLoader isInfinity. Most teams set it to something arbitrary (10, 50, 100) without measuring. Use your actual batch function latency to pick the right value.
Try it
npx dataloader-ai demo
No install, no account, no API key. The demo simulates a GraphQL server and prints live metrics to your terminal.
For your own server:
npm install dataloader-ai
Then swap DataLoader → DataLoaderAI with a name option. That's it.
Local mode: free forever, terminal metrics, no data leaves your machine
Cloud dashboard: free during beta, historical trends + alerts
SDK: MIT-licensed, (1,400+ downloads/month)
I'm the solo developer behind dataloader-ai. Built it because I kept running into the same observability gap in GraphQL servers. Would love feedback from anyone running DataLoader in production.
SOCIAL SHARE CARD GENERATOR