async
Higher-order async utility functions for callback, async/await, and promise-based control flow in Node.js and the browser.
Repository Health
Technical Analysis
Async is a widely-used JavaScript utility library providing around 70 functions for managing asynchronous control flow: collection iteration (each, map, filter, reduce, sortBy), control-flow composition (waterfall, series, parallel, auto), and concurrency utilities (queue, cargo, retry). Every function follows Node’s error-first callback convention while also transparently accepting native async functions and Promise-returning functions, and returns a Promise when no callback is supplied.
Originally created in 2010, before Promises or async/await existed in JavaScript, Async remains one of the most depended-upon packages in the npm ecosystem, still receiving maintenance and pulling over 100 million weekly downloads. Version 3 rewrote the internals as ES modules with full async-function support while preserving the same callback-first API that made it a de facto standard for pre-Promise Node.js code.
What You Get
- Around 70 async utility functions covering collections (each, map, filter, reduce, sortBy), control flow (series, parallel, waterfall, auto, race), and utilities (queue, cargo, retry, memoize)
- Uniform support for three calling conventions — Node-style error-first callbacks, native async/await functions, and Promises — mixed freely within the same call
- A dependency-graph task runner (auto/autoInject) that resolves execution order and concurrency automatically from named task requirements
- Bounded-concurrency primitives (queue, cargo, and *Limit variants) for throttling parallel work against rate limits or resource constraints
- Both a CommonJS build and a native ESM build (plus the separate async-es package), so the same API works in Node, bundlers, and directly in the browser
Common Use Cases
- Rate-limiting concurrent API calls with mapLimit/queue so a batch job doesn’t overwhelm a downstream service
- Orchestrating a multi-step startup sequence with auto, where some steps depend on the results of others finishing first
- Migrating or maintaining legacy Node.js callback-based codebases without rewriting call sites to promises
- Iterating over large collections asynchronously with eachSeries/mapSeries when operations must run in strict order, such as sequential file writes
Under The Hood
Architecture
Async’s roughly 5,500 lines under lib/ are organized one function per file (lib/auto.js, lib/queue.js, lib/waterfall.js, and so on), each a thin wrapper around shared primitives in lib/internal/: DoublyLinkedList.js backs the queue’s task list, wrapAsync.js/asyncify.js normalize callback-, async-function-, and Promise-returning iteratees into one internal calling convention, and eachOfLimit.js/parallel.js implement the concurrency-limited iteration loop that most collection functions delegate to. lib/index.js re-exports every public function. The dependency-graph runner in auto.js builds an adjacency structure over the tasks object and drives each task’s callback through once()/onlyOnce() guards, starting a task only once all its listed dependencies have resolved. Because nearly every public function is a shim over the same wrapAsync/eachOfLimit internals, a change to the calling-convention normalization or the queue’s internal linked-list would ripple through virtually the entire public API.
Tech Stack
The package ships with zero runtime dependencies — a deliberate choice for a foundational utility library — and relies on Babel (preset-es2015/es2017) to transpile the ES-module source under lib/ into the CommonJS dist/async.js published to npm, alongside a separate async-es package for pure-ESM consumers; Rollup produces the browser bundle. Testing runs on Mocha with Chai assertions and nyc coverage in Node, plus a parallel browser pass via Karma (karma-browserify, karma-firefox-launcher, karma-safari-launcher) exercising the same suite in real browsers. ESLint with @babel/eslint-parser enforces style, and GitHub Actions CI runs lint followed by the full test matrix on every push, with Coveralls tracking coverage. Documentation is generated via JSDoc from inline @name/@category annotations in each lib file.
Code Quality
The test/ directory mirrors lib/ almost one-to-one, with dozens of individual test cases per function covering callback-style, async-function, and Promise-based invocation paths plus explicit error-propagation and double-callback edge cases. Error handling is explicit throughout: internal helpers like once.js and onlyOnce.js exist specifically to guard against a callback being invoked twice, and wrapAsync.js/asyncify.js branch explicitly on whether a passed function is a plain callback function, an AsyncFunction, or an async generator rather than silently coercing mismatches. There is no static type system — plain ES modules, no TypeScript — but ESLint enforces consistent style, and CI runs the full Node and browser test suites on every push.
API Design Async’s defining design choice is accepting three different calling conventions — error-first callbacks, native async functions, and Promise-returning functions — through every one of its roughly 70 functions via the wrapAsync/asyncify normalization layer, and returning a Promise itself when no callback is supplied. Function naming is highly consistent: a base verb (each, map, filter, sortBy) composes with Series (strict sequential) and Limit (bounded concurrency) suffixes, so learning one function’s variants teaches the pattern for the rest of the library. This uniformity is also the biggest cost for newcomers today: because the library predates Promises and async/await in the language, much of its surface area (waterfall, auto, series) now solves a problem the language itself later absorbed. Documentation stays thorough regardless — a JSDoc-generated per-function reference plus inline @example blocks in every source file keep the boilerplate for adopting any single function low.
Used by 23 apps in this directory
Plasmic
CMS · Design Tools · Low Code Platforms
The open-source visual builder that lets teams design React apps and websites with drag-and-drop while integrating seamlessly with your codebase.
Promptfoo
AI Development
An open-source CLI and library for evaluating and red-teaming LLM applications — replace trial-and-error prompt engineering with systematic evals, vulnerability scanning, and CI/CD integration.
Social Analyzer
Security
Find and analyze a person's digital footprint across 1000+ social media platforms using multi-layer detection, OCR, and metadata extraction.
Unleash
Ab Testing Experimentation · Developer Tools · Devops
The open-source feature management platform that lets you ship code to production and control who sees it — without redeploying.
xyops
Automation · Monitoring
A unified, self-hosted platform for job scheduling, visual workflow automation, server monitoring, alerting, and incident response — built for teams who demand full ownership of their operations stack.