p-retry

Retry a promise-returning or async function with exponential backoff and fine-grained retry control.

Library
npm
v8.0.1
1,029stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
56/100Fair
Development Activity56
Maintenance28
Community52
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture90
Code Quality92
Innovation80
Learning Curve50

p-retry wraps any promise-returning or async function so that a failed call is retried automatically instead of propagating the first rejection. It applies exponential backoff by default, and exposes three independent hooks — shouldConsumeRetry, onFailedAttempt, and shouldRetry — so callers can decide whether a failure counts against the retry budget, react to each attempt (logging, custom delays), and decide whether to keep retrying at all, all without touching the core loop.

Beyond the default export, the package ships a makeRetriable helper that wraps an existing function so every call to it is retried transparently, and an AbortError class for signalling that retries should stop immediately with no further callbacks invoked. Retry timing integrates with AbortSignal for cancellation and with a monotonic clock (performance.now()) for maxRetryTime, so retries stop cleanly under both explicit cancellation and elapsed-time budgets regardless of system clock changes.

What You Get

  • A pRetry(input, options) function that retries a promise-returning function with configurable retries, factor, minTimeout, maxTimeout, and randomized jitter
  • Three composable hooks — shouldConsumeRetry, onFailedAttempt, shouldRetry — for controlling retry budget consumption, side effects on failure, and retry eligibility independently
  • An AbortError class for aborting all retries immediately from inside the retried function, with no further hooks invoked
  • AbortSignal support for cancelling in-flight retries from outside the retry loop
  • A maxRetryTime option measured with a monotonic clock so time budgets are immune to system clock adjustments
  • A makeRetriable(function, options) helper that wraps any function so every call is automatically retried without repeating options at each call site

Common Use Cases

  • Retrying flaky network requests (fetch calls) while treating 404s or other definitive failures as non-retryable via AbortError
  • Wrapping a database or API client call so transient errors are retried with backoff but validation errors fail immediately
  • Building a resilient job worker that retries a task a bounded number of times before giving up and reporting the last error
  • Retrying an operation only up to a wall-clock time budget (maxRetryTime) rather than a fixed attempt count

Under The Hood

Architecture p-retry is a single-file module (index.js, under 300 lines) exporting a default async function pRetry, a named makeRetriable higher-order wrapper, and an AbortError class. The core loop in pRetry runs a bounded while loop calling the caller-supplied input(attemptNumber) function and routing any rejection through a dedicated onAttemptFailure helper that sequences shouldConsumeRetry, then onFailedAttempt, then shouldRetry — each of which can independently veto a retry, throw to abort immediately, or return a promise to defer. Delay math (calculateDelay) and remaining-time tracking (calculateRemainingTime, built on performance.now() for a monotonic clock) are extracted into small pure functions, and delayForRetry manages the actual setTimeout/AbortSignal race. There is no persistent internal state beyond function-local closures and no dependency injection; the load-bearing abstraction is the attempt loop’s error-classification order (AbortError, then non-network TypeError, then everything else), and changing that ordering would silently change retry semantics for every consumer that relies on TypeErrors from fetch-like APIs being retried only when they represent network failures.

Tech Stack A pure ESM package (type: module) targeting Node.js 22+, with a single runtime dependency, is-network-error, used to distinguish network TypeErrors from other TypeErrors for retry eligibility. Development tooling follows the author’s standard setup: ava as the test runner, xo (an opinionated ESLint config) for linting, tsd for testing the hand-written index.d.ts type definitions, execa for spawning subprocesses in tests, and delay as a test utility. There is no build step — index.js ships directly to npm as declared in the package’s files field. CI (GitHub Actions) runs the full npm test script (xo && ava && tsd) across Node.js 22 and 24.

Code Quality test.js contains extensive coverage (57 distinct test cases) exercising backoff/delay math, AbortError and AbortController interplay, the ordering and interaction of the three retry hooks, non-Error throws, and the removed forever option. This is paired with tsd-based type tests validating the public type surface and xo lint enforcement in CI. Error handling is explicit and typed throughout — invalid options throw descriptive TypeError instances via small dedicated validator functions rather than failing silently or coercing bad input. Naming is consistent and self-documenting across the module.

API Design The standout design choice is splitting failure handling into three independent, composable hooks — shouldConsumeRetry (does this failure count against the budget), onFailedAttempt (side effects like logging or a manual delay), and shouldRetry (should retrying continue at all) — rather than the single catch-all callback most retry libraries expose. Combined with first-class AbortSignal support woven directly into the delay logic (not bolted on after the fact), a monotonic-clock-based maxRetryTime immune to system clock skew, and the makeRetriable wrapper for turning any function into a self-retrying one without re-specifying options per call, the public API stays small while covering cases most retry utilities require workarounds for.

Used by 10 apps in this directory

TypeScript
92%
MIT

Dittofeed

Marketing · Automation

2,926

Open-source omni-channel customer engagement platform for automating transactional and marketing messages via email, SMS, WhatsApp, Slack, and mobile push.

View details
54
Repo Health
75
Technical
62
Dependency
Built with
TypeScript92%
Updated 5 months ago
TypeScript
99%
MIT

GraphQL Hive

Developer Tools · Devops · Monitoring

484

Open-source GraphQL schema registry and observability platform with breaking change detection, federation support, and CI/CD integration for teams of any size.

View details
89
Repo Health
81
Technical
69
Dependency
Built with
TypeScript99%
Updated 2 days ago
TypeScript
98%
Other

Kibana

Analytics · Monitoring

21,284

Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.

View details
98
Repo Health
87
Technical
66
Dependency
Built with
TypeScript98%
Updated yesterday
TypeScript
97%
MPL 2.0

Logto

Authentication

14,510

Open-source auth infrastructure for SaaS and AI apps with OIDC, SAML, and RBAC

View details
91
Repo Health
83
Technical
63
Dependency
Built with
TypeScript97%
Updated yesterday
TypeScript
99%
Apache 2.0

Mastra Code

AI Code Assistants

27,743

"A coding agent that never compacts" — a terminal-based AI coding agent built on the Mastra framework, with Observational Memory instead of context compaction, multi-model support, and OAuth login for Claude Max or ChatGPT Plus.

View details
88
Repo Health
73
Technical
65
Dependency
Built with
TypeScript99%
Updated today
TypeScript
94%
Apache 2.0

NemoClaw

AI Agents · AI Development

22,388

Run AI coding agents like OpenClaw and Hermes securely inside NVIDIA OpenShell sandboxes with a hardened blueprint, routed inference, and lifecycle management through a single CLI.

View details
73
Repo Health
87
Technical
71
Dependency
Built with
TypeScript94%
Updated today
Rust
71%
Apache 2.0

Rivet

AI Agents · Developer Tools

6,116

Stateful actors as a primitive for AI agents, real-time collaboration, and durable execution — with in-memory state, WebSockets, queues, and scheduling built in.

View details
86
Repo Health
81
Technical
65
Dependency
Built with
Rust71%
TypeScript25%
Updated yesterday
TypeScript
99%
Apache 2.0

Trigger.dev

Automation · AI Development · Developer Tools

16,223

Build and deploy fully-managed AI agents and background jobs in TypeScript — with no timeouts, durable retries, real-time observability, and elastic scaling built in.

View details
90
Repo Health
9
Technical
63
Dependency
Built with
TypeScript99%
Updated today
TypeScript
85%
Other

Webiny JS

Ecommerce · Blogging · CMS

8,032

Open-source, self-hosted CMS on AWS serverless — a TypeScript framework you extend with code, not a product you configure through a UI.

View details
90
Repo Health
86
Technical
62
Dependency
Built with
TypeScript85%
JavaScript14%
Updated yesterday

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search