p-limit
A tiny, battle-tested utility for running async functions with a strict concurrency limit.
Repository Health
Technical Analysis
p-limit is a minimal utility for controlling how many promise-returning or async functions run at once. Instead of firing off every task simultaneously and overwhelming an API, database, or file system, you wrap each call with a limit() function that queues work beyond a fixed concurrency ceiling and lets it through as earlier tasks finish.
Created by Sindre Sorhus and used across a huge share of the JavaScript ecosystem, p-limit has become a de facto way to throttle concurrent async work in Node.js and the browser. The current version adds a map() helper for batch processing, an options object with rejectOnClear, and a runtime-adjustable concurrency setter, while keeping the core API to a single function call.
What You Get
- Simple wrapper API - Call
limit(fn, ...args)to schedule any async function under the concurrency ceiling; no class instantiation or setup required. - Built-in
map()helper -limit.map(iterable, mapperFunction)batches an iterable through the same limiter in one call, replacing manualPromise.allplus.map()boilerplate. - Live introspection -
activeCountandpendingCountgetters let you report progress or debug queue backpressure while tasks are running. - Runtime-adjustable concurrency - The
concurrencyproperty is a live setter, so you can raise or lower the limit in response to rate-limit responses without rebuilding the limiter. - Graceful shutdown support -
clearQueue()discards pending (not yet started) tasks, with an optionalrejectOnClearmode that rejects them with anAbortErrorinstead of leaving them unresolved.
Common Use Cases
- Throttling third-party API calls - Cap concurrent HTTP requests to an external service so you don’t trip its rate limiter.
- Batch file or database operations - Process large lists of files, rows, or records without opening thousands of simultaneous file handles or DB connections.
- Web scraping and crawling - Limit how many pages a crawler fetches at once to avoid overwhelming the target server or the local network.
- Bounding fan-out in serverless functions - Keep concurrent downstream calls under a function’s connection or memory limits.
Under The Hood
Architecture
p-limit is a single ~130-line ESM module (index.js) built as a closure-based state machine rather than a class. The pLimit(concurrency) factory returns a generator function decorated via Object.defineProperties with activeCount, pendingCount, clearQueue, a live concurrency getter/setter, and map. Internally, enqueue pushes a {reject, run} item onto a yocto-queue instance and calls resumeNext, which dequeues and runs items while activeCount is under the limit; run invokes the wrapped function, resolves the caller’s promise immediately with the inner result promise (so callers don’t wait for scheduling), then awaits completion before calling next to decrement activeCount and pull the next item. This inversion — resolving with a promise-of-a-promise rather than the awaited value — is what lets p-limit preserve async execution context (verified in tests via AsyncLocalStorage) without extra bookkeeping.
Tech Stack
The package ships pure ESM ("type": "module") with a single runtime dependency, yocto-queue, a linked-list-based FIFO queue chosen to avoid the O(n) cost of Array.prototype.shift() on large backlogs. It targets Node.js >=20 and browsers with no transpilation or bundling step — index.js and a hand-written index.d.ts are published as-is. Development tooling is Sindre Sorhus’s standard set: xo for linting (a strict, zero-config ESLint preset), ava for tests, and tsd for type-level tests against index.d.ts.
Code Quality
test.js is extensive relative to the module’s size, covering concurrency limits under real timing assertions (time-span, in-range), async-context propagation, error propagation through Promise.all, clearQueue with and without rejectOnClear, dynamic concurrency changes (both raising and lowering mid-run), and every map() variant (arrays, Set, iterators, detached from limit). Type safety is enforced separately via index.test-d.ts and tsd. No swallowed errors: the one catch {} in run() is deliberately commented as intentional, to prevent unhandled rejections while preserving the original rejection for the caller’s own promise.
API Design
The public surface is deliberately tiny: a single default export function that returns a callable object, plus one named export (limitFunction) for the single-function-owns-its-concurrency case. Optional behavior (rejectOnClear) is exposed through an options object rather than extra positional parameters, and state is exposed as plain getters/setters (activeCount, concurrency) instead of methods. Getting started requires one line (const limit = pLimit(5)), and recipes.md documents eight real-world patterns (batch processing, graceful shutdown, dynamic concurrency, shared context, progress reporting) beyond the core README, which is unusually thorough documentation for a package this small.
Used by 45 apps in this directory
Papra
Bookmarks Archiving
Self-hosted document archiving with email ingestion, OCR full-text search, and pluggable storage — store once, find anything.
paseo
AI Agents · AI Code Assistants
One unified interface to orchestrate Claude Code, Codex, Copilot, OpenCode, and Pi agents in parallel from desktop, mobile, or the terminal.
Payload CMS
Blogging · CMS · Developer Tools
The open-source, Next.js-native headless CMS that lives inside your /app folder and gives you a full TypeScript backend instantly.
Penpot
Design Tools
Open-source design platform with GPU-accelerated canvas, native design tokens, and MCP-powered AI workflows for teams that ship fast.
PostHog
Ab Testing Experimentation · Analytics · Developer Tools
The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.
Postiz
Automation · Social Media
The agentic social media scheduler — AI-powered content creation, 33-platform posting, and team workflows, all self-hosted.
reader
Data Engineering · Developer Tools
Production-grade open source web scraping engine that turns any URL into clean markdown for AI agents — with built-in anti-bot bypass, proxy rotation, and browser session management.
Refly
AI Development · Automation · No Code Platforms
Build deterministic, versioned agent skills from natural language—run them anywhere from Claude Code to Slack.
Rocket.Chat
Team Chat
The secure, self-hosted team communications platform for organizations that cannot compromise on data sovereignty.