{"id":49497,"library":"tenacious-fetch","title":"tenacious-fetch","description":"Tiny fetch API wrapper (ESM) adding retry with exponential backoff, configurable timeout, and custom retry strategies. Current stable version 2.3.1, lightweight (~3KB gzipped), zero runtime dependencies. Supports both browser and Node.js (fetch-compatible). Differentiators: minimal overhead, terse API, and full TypeScript definitions (since v2).","status":"active","version":"2.3.1","language":"javascript","source_language":"en","source_url":"https://github.com/tiaanduplessis/tenacious-fetch","tags":["javascript","fetch","fetch-wrapper","timeout","retries","retry","fetch-retry"],"install":[{"cmd":"npm install tenacious-fetch","lang":"bash","label":"npm"},{"cmd":"yarn add tenacious-fetch","lang":"bash","label":"yarn"},{"cmd":"pnpm add tenacious-fetch","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Default export only; package is ESM-only since v2.","wrong":"const { tenaciousFetch } = require('tenacious-fetch')","symbol":"tenaciousFetch","correct":"import tenaciousFetch from 'tenacious-fetch'"},{"note":"Use 'import type' for TypeScript to avoid emitting runtime code.","wrong":"import { TenaciousOptions } from 'tenacious-fetch'","symbol":"interface TenaciousOptions","correct":"import type { TenaciousOptions } from 'tenacious-fetch'"},{"note":"When using dynamic import in Node ESM.","wrong":"const tenaciousFetch = require('tenacious-fetch').default","symbol":"tenaciousFetch","correct":"const { default: tenaciousFetch } = await import('tenacious-fetch')"},{"note":"CJS import works via default export compatibility (package.json 'exports' field provides CommonJS wrapper).","wrong":null,"symbol":"tenaciousFetch","correct":"const tenaciousFetch = require('tenacious-fetch')"}],"quickstart":{"code":"import tenaciousFetch from 'tenacious-fetch';\n\nasync function main() {\n  const url = 'https://jsonplaceholder.typicode.com/todos/1';\n  const options = {\n    retries: 3,\n    retryDelay: 1000, // ms between retries\n    timeout: 5000, // total request timeout\n    onRetry: (attempt, error) => {\n      console.log(`Retry attempt ${attempt} after error: ${error}`);\n    },\n  };\n  try {\n    const response = await tenaciousFetch(url, options);\n    const data = await response.json();\n    console.log('Success:', data);\n  } catch (error) {\n    console.error('Failed after retries:', error);\n  }\n}\nmain();","lang":"typescript","description":"Shows a basic GET request with 3 retries, 1s delay, and 5s timeout using the default export."},"warnings":[{"fix":"Use import syntax; if using CommonJS, use dynamic import via async function or update package.json to include 'type': 'module'.","message":"tenacious-fetch v2 changed from CommonJS to ESM-only. Direct require() will fail unless using Node >=14 with experimental modules or a compatible bundler.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Calculate per-attempt timeout manually if needed, or use a custom retry strategy.","message":"The 'timeout' option applies to the total request duration including retries, not per attempt. This can cause unexpected early termination.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Replace `retryMethod` with `retryStrategy` returning true/false.","message":"The 'retryMethod' option was deprecated in v2.3.0; use 'retryStrategy' instead (function returning boolean).","severity":"deprecated","affected_versions":">=2.3.0"},{"fix":"Install a fetch polyfill like `node-fetch` or `cross-fetch` and assign to globalThis before using.","message":"If the fetch API is not globally available (e.g., older Node versions), tenacious-fetch will throw a ReferenceError. It does not polyfill fetch.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"search_vec":"'2.3.1':23 '3kb':25 'ad':9 'api':6,42 'backoff':13 'browser':32 'compat':37 'configur':14 'current':20 'custom':17 'definit':46 'depend':29 'differenti':38 'esm':8 'exponenti':12 'fetch':3,5,36,50,52,58 'fetch-compat':35 'fetch-retri':57 'fetch-wrapp':51 'full':44 'gzip':26 'javascript':49 'lightweight':24 'minim':39 'node.js':34 'overhead':40 'retri':10,18,55,56,59 'runtim':28 'sinc':47 'stabl':21 'strategi':19 'support':30 'tenaci':2 'tenacious-fetch':1 'ters':41 'timeout':15,54 'tini':4 'typescript':45 'v2':48 'version':22 'wrapper':7,53 'zero':27","created_at":"2026-06-07T17:02:04.154183+00:00","updated_at":"2026-06-07T17:02:04.154183+00:00","problems":[{"fix":"Add `\"type\": \"module\"` to your package.json, or rename file to .mjs, or use dynamic import.","cause":"Using ES import syntax in a CommonJS file without enabling ESM support.","error":"SyntaxError: Cannot use import statement outside a module"},{"fix":"Use `import tenaciousFetch from 'tenacious-fetch'` (default import) instead of `import { tenaciousFetch } from 'tenacious-fetch'`.","cause":"Using named import instead of default import.","error":"TypeError: tenaciousFetch is not a function"},{"fix":"Install and import a fetch polyfill before using tenacious-fetch, e.g., `import 'node-fetch'` or `import 'cross-fetch/polyfill'`.","cause":"tenacious-fetch expects a global fetch implementation; missing in Node <18 or some environments.","error":"ReferenceError: fetch is not defined"}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":null,"cli_version":null,"type":"library","homepage":"https://github.com/tiaanduplessis/tenacious-fetch","github":"https://github.com/tiaanduplessis/tenacious-fetch","docs":null,"changelog":null,"pypi":null,"npm":"tenacious-fetch","openapi_spec":null,"status_page":null,"smithery":null,"categories":["devops"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-07","next_check":"2026-09-05","install_tag":null}}