npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fetch-retrier

v0.3.1

Published

A lightweight wrapper around `fetch` that adds **retries**, **per-attempt timeout**, and **full jitter** backoff. Pass standard `RequestInit` options (`method`, `body`, `credentials`, and more) for POST/PUT APIs and other HTTP calls that may be rate-limit

Readme

Fetch Retrier

A lightweight wrapper around fetch that adds retries, per-attempt timeout, and full jitter backoff. Pass standard RequestInit options (method, body, credentials, and more) for POST/PUT APIs and other HTTP calls that may be rate-limited (429) or temporarily unavailable (5xx).

npm version npm downloads build release

Features

  • Configurable retries – Set the maximum number of attempts per request.
  • Per-attempt timeout – Abort each attempt when it exceeds a given duration.
  • Full jitter backoff – Exponential backoff with random jitter (AWS-style) between retries.
  • RequestInit forwarding – Pass method, body, credentials, redirect, and other fetch options via init on every attempt.
  • Header shorthand – Optional top-level headers override init.headers when both are set.
  • Custom retry predicate – Control which responses trigger a retry (default: 429, 500, 502, 503, 504).
  • External cancellation – Pass an AbortSignal to cancel in-flight requests.
  • Typed errorsFetchRetrierHttpError, FetchRetrierNetworkError, FetchRetrierAbortError, and related classes.
  • TypeScript – Exported types including RequestOptions and FetchInitOptions.

Installation

npm

npm install fetch-retrier

yarn

yarn add fetch-retrier

Usage

GET request

import { fetchRetrier, RequestOptions } from 'fetch-retrier';

const options: RequestOptions = {
  retries: 3,
  timeoutMs: 5000,
  baseBackoffMs: 1000,
  headers: {
    Authorization: 'Bearer token',
  },
};

const response = await fetchRetrier('https://api.example.com/data', options);

if (response.ok) {
  const data = await response.json();
}

POST with JSON body (init)

import { fetchRetrier } from 'fetch-retrier';

const response = await fetchRetrier('https://api.example.com/items', {
  retries: 3,
  timeoutMs: 5000,
  baseBackoffMs: 1000,
  init: {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'example' }),
    credentials: 'include',
  },
});

const item = await response.json();

The same init (including body) is applied on every retry attempt. Per-attempt signal and timeout are managed internally.

Custom retry logic

const response = await fetchRetrier('https://api.example.com/data', {
  retries: 5,
  timeoutMs: 10000,
  baseBackoffMs: 500,
  shouldRetry: (res, body) => {
    if ([429, 500, 502, 503].includes(res.status)) return true;
    if (res.status === 200 && body.includes('"retry": true')) return true;
    return false;
  },
});

Cancellation with AbortController

const controller = new AbortController();

setTimeout(() => controller.abort(), 250);

await fetchRetrier('https://api.example.com/data', {
  retries: 3,
  timeoutMs: 5000,
  baseBackoffMs: 250,
  signal: controller.signal,
});

Retry and error behavior

  • Success – If response.ok is true, the response is returned immediately.
  • Retriable failure – If the response is not OK and shouldRetry(response, body) returns true, the client waits (full jitter backoff) and retries until retries is exhausted. On the last attempt, FetchRetrierHttpError is thrown (includes status).
  • Non-retriable failure – If shouldRetry returns false, FetchRetrierHttpError is thrown immediately (e.g. Non-retriable HTTP error: 404).
  • Timeout – If a request exceeds timeoutMs, it is aborted and retried until retries is exhausted; the final failure is FetchRetrierAbortError.
  • Network / TypeError – Network errors are retried with backoff; after the last attempt, FetchRetrierNetworkError is thrown with the original error as cause.
  • Already aborted signal – If signal is already aborted before an attempt starts, FetchRetrierAlreadyAbortedError is thrown (no attempt is made).

Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | retries | number | Yes | Maximum number of attempts (including the first request). | | timeoutMs | number | Yes | Timeout in milliseconds for each attempt. Exceeded attempts are aborted and retried. | | baseBackoffMs | number | Yes | Base delay in milliseconds for backoff. Delay is capped at baseBackoffMs * 2^attempt and randomized (full jitter). | | init | FetchInitOptions | No | fetch options forwarded to every attempt: method, body, credentials, redirect, mode, cache, etc. signal is reserved for internal timeout and cancellation. | | headers | Record<string, string> | No | Headers sent on every attempt. Overrides init.headers when both are set. | | signal | AbortSignal | No | External abort signal. If already aborted, FetchRetrierAlreadyAbortedError is thrown. If aborted during an attempt, the request is aborted and retried until retries is exhausted. | | shouldRetry | (response: Response, body: string) => boolean | No | Called after response.text() when response.ok is false. Return true to retry. Default: 429, 500, 502, 503, 504. |

Requirements

  • Node.js >= 20.0.0
  • Uses the global fetch (available in Node 18+)

License

This project is licensed under the (Apache-2.0) License.