HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
graphql
dataloader
JavaScript2015–2026
graphql / dataloader

dataloader

DataLoader is a generic utility to be used as part of your application's data fetching layer to provide a consistent API over various backends and reduce requests to those backends via batching and caching.

37Distinct people
37Mentions
0Explicit recommenders
13.4KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

DataLoader is a generic utility to be used as part of your application's data fetching layer to provide a consistent API over various backends and reduce requests to those backends via batching and caching.

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 6:01:08 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year37 dated mentions

Observed mentions: 2015-09-14 19:03:03 UTC to 2026-02-19 19:45:34 UTC.

02468102015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 3 mentions; 1 submissions, 2 comments20152016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 9 mentions; 0 submissions, 9 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC312
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC505
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC909
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC202
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC303
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC404
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC303
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC101
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC303
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC202
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC101
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
DataLoader DataLoader is a generic utility to be used as part of your application's data fetching layer to provide a simplified and consistent API over various remote data sources such as databases or web services via batching and caching. A port of the "Loader" API originally developed by @schrockn at Facebook in 2010 as a simplifying force to coalesce the sundry key-value store back-end APIs which existed at the time. At Facebook, "Loader" became one of the implementation details of the "Ent" framework, a privacy-aware data entity loading and caching layer within web server product code. This ultimately became the underpinning for Facebook's GraphQL server implementation and type definitions. DataLoader is a simplified version of this original idea implemented in JavaScript for Node.js services. DataLoader is often used when implementing a graphql-js service, though it is also broadly useful in other situations. This mechanism of batching and caching data requests is certainly not unique to Node.js or JavaScript, it is also the primary motivation for Haxl, Facebook's data loading library for Haskell. More about how Haxl works can be read in this blog post. DataLoader is provided so that it may be useful not just to build GraphQL services for Node.js but also as a publicly available reference implementation of this concept in the hopes that it can be ported to other languages. If you port DataLoader to another language, please open an issue to include a link from this repository. Getting Started First, install DataLoader using npm. npm install --save dataloader To get started, create a DataLoader. Each DataLoader instance represents a unique cache. Typically instances are created per request when used within a web-server like express if different users can see different things. Note: DataLoader assumes a JavaScript environment with global ES6 Promise and Map classes, available in all supported versions of Node.js. Batching Batching is not an advanced feature, it's DataLoader's primary feature. Create loaders by providing a batch loading function. const DataLoader = require('dataloader'); const userLoader = new DataLoader(keys => myBatchGetUsers(keys)); A batch loading function accepts an Array of keys, and returns a Promise which resolves to an Array of values*. Then load individual values from the loader. DataLoader will coalesce all individual loads which occur within a single frame of execution (a single tick of the event loop) and then call your batch function with all requested keys. const user = await userLoader.load(1); const invitedBy = await userLoader.load(user.invitedByID); console.log(`User 1 was invited by ${invitedBy}`); // Elsewhere in your application const user = await userLoader.load(2); const lastInvited = await userLoader.load(user.lastInvitedID); console.log(`User 2 last invited ${lastInvited}`); A naive application may have issued four round-trips to a backend for the required information, but with DataLoader this application will make at most two. DataLoader allows you to decouple unrelated parts of your application without sacrificing the performance of batch data-loading. While the loader presents an API that loads individual values, all concurrent requests will be coalesced and presented to your batch loading function. This allows your application to safely distribute data fetching requirements throughout your application and maintain minimal outgoing data requests. Batch Function A batch loading function accepts an Array of keys, and returns a Promise which resolves to an Array of values or Error instances. The loader itself is provided as the this context. async function batchFunction(keys) { const results = await db.fetchAllKeys(keys); return keys.map(key => results[key] || new Error(`No result for ${key}`)); } const loader = new DataLoader(batchFunction); There are a few constraints this function must uphold: The Array of values must be the same length as the Array of keys. Each index in the Array of values must correspond to the same index in the Array of keys. For example, if your batch function was provided the Array of keys: [ 2, 9, 6, 1 ], and loading from a back-end service returned the values: { id: 9, name: 'Chicago' } { id: 1, name: 'New York' } { id: 2, name: 'San Francisco' } Our back-end service returned results in a different order than we requested, likely because it was more efficient for it to do so. Also, it omitted a result for key 6, which we can interpret as no value existing for that key. To uphold the constraints of the batch function, it must return an Array of values the same length as the Array of keys, and re-order them to ensure each index aligns with the original keys [ 2, 9, 6, 1 ]: [ { id: 2, name: 'San Francisco' }, { id: 9, name: 'Chicago' }, null, // or perhaps `new Error()` { id: 1, name: 'New York' }, ]; Batch Scheduling By default DataLoader will coalesce all individual loads which occur within a single frame of execution before calling your batch function with all requested keys. This ensures no additional latency while capturing many related requests into a single batch. In fact, this is the same behavior used in Facebook's original PHP implementation in 2010. See enqueuePostPromiseJob in the source code for more details about how this works. However sometimes this behavior is not desirable or optimal. Perhaps you expect requests to be spread out over a few subsequent ticks because of an existing use of setTimeout, or you just want manual control over dispatching regardless of the run loop. DataLoader allows providing a custom batch scheduler to provide these or any other behaviors. A custom scheduler is provided as batchScheduleFn in options. It must be a function which is passed a callback and is expected to call that callback in the immediate future to execute the batch request. As an example, here is a batch scheduler which collects all requests over a 100ms window of time (and as a consequence,
Read the full README on GitHub

What Hacker News says

9 sources
(Author of the post here) Thanks for the notes! > And immediately after that the article spends two pages of text explaining how insanely complex the "becomes easy with GraphQL" really is, and offers no actual details on the "easy" part. Hi, thanks for this piece of feedback! I could have done a better job here, since I was summarizing a 38 min talk into a few paragraphs. These parts are actually talking about different concepts: The first is about ensuring that a single fetch from the UI knows about all the data it needs, so you can easily avoid multiple roundtrips to the database. This is something you can do with a basic in-process caching tool called DataLoader: https://github.com/facebook/dataloader The second is about caching _across_ requests, something that people usually have special infrastructure for in REST, such as Varnish. T
Read the rest
his talk was elaborating on how a GraphQL-specific piece of caching infrastructure might work, and sit in exactly the same place as REST caching. > Oh, your client has to be cache aware. I think the intention was to say that it _could_ be cache aware. It doesn't need to be, but you end up with a really nice situation. > I would love to see an explanation how GraphQL makes caching for this easy. My intention here was to say that GraphQL's ability to understand what fields are being asked for makes it easy to return specific cache controls, rather than having to put one on the whole query. So your server basically generates the control for you (this is something that exists today) > It's called REST APIs and we've known how to do them since 2001. I don't think REST has a way to automatically combine multiple REST services, and then query them all in one HTTP request without multiple roundtrips to the client, which was the goal here. Happy to talk more, and thank you for bringing up some of the places where I can communicate more clearly in the future! The audience of the talk was a GraphQL conference, but I should definitely consider next time that people who aren't already bought into the idea of GraphQL will be taking a look as well.
In The GraphQL stack: How everything fits together
The solution for authorization/access control is to use "Dataloader" [1] which is also made by Facebook. You write a single source of truth for how authorization is handled, and make sure that graphql resolves with this source. Dataloader is not as well known as GraphQL, but crucial for complex authorization systems imo. It also has a bunch of other features like batching and caching which makes your life easier when opting for this solution. [1]: https://github.com/facebook/dataloader
In The GraphQL stack: How everything fits together
Client UX is king for a large majority of user facing applications. And that's where client-centric query mechanisms like GraphQL/Falcor/Om.next make the most sense. The point is exactly to push data fetching complexity from the Client to the API server. And that's generally a worthwhile tradeoff for these applications because you can deal with server complexity by throwing more money at your API server cluster, but you can't force your users to upgrade to more performant clients. Of course, server-side overfetching is a problem that can drastically limit the scalability of your system by overloading the components you can't as easily scale by spinning up more machines (i.e. most databases). Naive implementations of GraphQL on the server can be ridiculously chatty and require multiple server-db roundtrips to resolve even the simplest of q
Read the rest
ueries, which can arguably be an even nastier problem than dealing with multiple client-server roundtrips with a RESTful API. This is why non-trivial GraphQL servers generally use some kind of resolver batching/caching layer (Facebook provides a library called DataLoader to facilitate this: https://github.com/facebook/dataloader) or a query planner at your root resolver (like Join Monster: https://github.com/stems/join-monster). Neither of these approaches is trivial to implement, but then again, doing efficient data fetching on the client against a RESTful API is just as difficult, if not more so. Efficient data-fetching is just a very difficult problem, and involves essential complexity that needs to live somewhere. At the end of the day it's up to you if you want to deal with that complexity in your clients (using a traditional RESTful API) or on your API servers (using a query mechanism like GraphQL).
In JrGQL, a GraphQL alternative
I'm genuinely surprised by the number of people on HN who seem to know very little about what has been safe to call the successor to REST for quite some time. Forgive me if this sounds hyperbolic, but unless you have unusual or strict requirements, building a new app in 2017 REST-first is most likely a terrible mistake. Let me clear up some misconceptions I see in almost every HN comment thread on GraphQL: 1. GraphQL isn't more suited to Graph databases. Your data sources can be a mix of relational DB, NoSQL, key value, a REST API, or anything else. 2. n+1 has always been a solved problem in GraphQL thanks to DataLoader[1], a query batching utility which coalesces calls to your data sources from different parts of your app, specifically to avoid n+1. 3. It's unquestionably production-ready, battle-tested, has a real spec and official refe
Read the rest
rence implementation, and it's probably the safest bet you can make at this moment in an industry as fickle as this. With GraphQL you simply write your schema, define types and relationships, and you’re then able to request data in almost any shape you wish, with very little extra work. This is invaluable during development. If you have a list of recent comments with author names, and later decide to show an avatar alongside the name, you don’t need to write any extra code on the server. You add an extra line to your query (or component’s fragment) on the client. The same goes for any field, any relationship, no matter how complex the resulting shape. If you wanted a comment author’s follower’s comments’ likeCounts, you still don’t need to write another line of server code. This makes it stupidly simple to rapidly prototype new features, try out new layouts, and means you can share a single API endpoint between mobile apps and desktop site without sending useless data to one or both. There have been many occasions when we simply wouldn't have had the time to implement a feature correctly with REST, particularly when we might not even know what data we'll want until we begin developing the feature and get a feel for how it works. It doesn't just save server dev time either. On the client side there are libraries like Apollo[2] and Relay which take care of fetching data, caching, normalization, and you should almost certainly use one (I recommend Apollo) unless you have a good reason not to. Writing fetch calls and managing your store manually is just going to be a huge waste of time. And the spec is more than queries and mutations. It's subscriptions, live queries, and more [3]. Real-time data is a first-class citizen of GraphQL, and the two most popular front-end libraries have official implementations of subscriptions (with live queries in progress). GraphQL is elegant, has a well-designed official spec, great DX and just plain makes sense. But it's really something you need to try out for yourself (preferably on a real project) to see just how great it is. If you’re planning to build something new with REST, seriously, reconsider. There's a slightly higher upfront cost to using GraphQL (particularly if you're new to it), but once you settle into it you'll be glad you did. Useful tools and resources: - GraphiQL[4] - an incredibly useful tool for running queries on your GraphQL API - Graph.cool[5] - BaaS for quickly prototyping a GraphQL API - Apollo Launchpad[6] - Try out GraphQL server code in your browser [1] https://github.com/facebook/dataloader [2] https://github.com/apollographql/apollo-client [3] https://dev-blog.apollodata.com/new-features-in-graphql-batc... [4] https://github.com/graphql/graphiql [5] https://www.graph.cool [6] http://launchpad.graphql.com
In Ask HN: What tech that's right around the corner are you most excited about?
There are basically two approaches to this issue: 0) Do nothing If you are just prototyping, you should do the simplest thing that could possibly work. (But this is not a real solution, so I won't count it) 2) Request Batching This approach is popularised by Facebooks Dataloader library https://github.com/facebook/dataloader Instead of directly querying the database in the resolver, you return a specification of what data you are interested in. When all resolvers on the same level in the query has returned this specification, the Dataloader library figures out how to batch queries together as much as possible 3) Big Join You can inspect the GraphQL query in the top level resolver and basically perform one giant join up front. You will then pass the entire value down your resolve hierarchy, and all they have to do is pick out the correct d
Read the rest
ata from the complete result set. Take a look at join-monster if you are interested in this approach. The Graphcool hosted backend is serving millions of requests an hour using the Dataloader approach, and we have found this to be more flexible and more performant at scale than generating a big complex join up front. For most queries we see single digit millisecond response time for a batched query, and the time complexity scales linearly with the depth of the query, which is not the case for joins.
In Apollo Server 1.0  – GraphQL Server for Node.js Frameworks
I'm interested in learning solutions for this as well, but it's hard to find because most GraphQL tutorials stop at the resolver level. There are a couple approaches I've seen for mapping to an SQL backend. One is batching - You get the top level resources, then save their accosted record IDs until later so you can make fewer calls to get their associations. This still makes quite a few database calls, especially for deeper queries or many different type of objects. Another approach is "whole tree up-front" where you take the AST of the graph you're trying to resolve, and convert that to one big SQL query that joins all the associated objects. This can be more performant in some situations as it only makes a single database query, but a drawback is that larger queries eat up a more bandwidth from your query since having many joins causes
Read the rest
data duplication. Another drawback is that having a single query makes it so you can't cache each resolver individually like you might be able to do with a batching solution. I don't have all my links handy but here's one you can check out: https://github.com/facebook/dataloader If anyone has something to add please chime in! I'd love to hear how people are really using GraphQL with SQL backends!
In How to GraphQL – A Fullstack Tutorial for GraphQL

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.