Repo of the Day
fetch-kit/ffetch: TypeScript-first fetch wrapper with configurable timeouts, retries, and circuit-breaker baked in.
Published: Mar 26, 2026
Open repository ↗TypeScript-first fetch wrapper with configurable timeouts, retries, and circuit-breaker baked in. - fetch-kit/ffetch
Summary
@fetchkit/ffetch is a TypeScript-first wrapper around the Fetch API that adds production-grade resilience without abandoning the standard fetch model. It is small (around 3kb minified, zero runtime dependencies) and ships as dual ESM/CJS, wrapping native fetch or any fetch-compatible implementation. Optional plugins layer on features like circuit breaking, in-flight request deduplication, request hedging, and bulkheading, so engineers pay for only what they use.
What it is useful for
It closes the gap between native fetch (which has no built-in timeout or retry) and heavier HTTP clients. Engineers can keep the Response-based flow they already know while opting into safety features incrementally. The README highlights typical use cases: microservices that need timeout and retry control, high-traffic clients that benefit from deduping identical concurrent requests, and SSR/edge apps that must inject a runtime-specific fetch. The package works in Node.js, browsers, Cloudflare Workers, and React Native, and exposes specific error classes — TimeoutError, RetryLimitError, CircuitOpenError, BulkheadFullError, HttpError, NetworkError, AbortError — for precise catch blocks.
How engineers can use it
Install with any of the documented package managers:
npm install @fetchkit/ffetch
A minimal client takes timeouts and retries straight in the constructor:
import { createClient } from '@fetchkit/ffetch'
const api = createClient({ timeout: 5000, retries: 2 })
const response = await api('https://api.example.com/users')
For production-style setup, the README demonstrates layering plugins through the plugins array. The example below combines deduplication, a circuit breaker, and request shortcuts:
import { createClient } from '@fetchkit/ffetch'
import { dedupePlugin } from '@fetchkit/ffetch/plugins/dedupe'
import { circuitPlugin } from '@fetchkit/ffetch/plugins/circuit'
const api = createClient({
timeout: 10_000,
retries: 2,
plugins: [
dedupePlugin({ ttl: 30_000, sweepInterval: 5_000 }),
circuitPlugin({ threshold: 5, reset: 30_000 }),
],
})
Lifecycle hooks (before, after, onError) cover logging, auth, and metrics. The fetchHandler option accepts any fetch-compatible function (for example node-fetch or a framework-scoped fetch), which is useful for SSR and metaframeworks. With responseShortcutsPlugin(), parsing becomes api(url).json(); with requestShortcutsPlugin(), calls like api.get(url) are available.
Documented limitations to keep in mind: deduplication is off by default and is skipped for ReadableStream, FormData, and Blob bodies; it should also be used cautiously with non-idempotent methods. The library expects AbortSignal.any, available natively in Node.js 20.6+ and modern browsers — older runtimes need the abort-controller-x polyfill. The project is MIT-licensed, but the README is the authoritative source for full options, so consult the linked docs for deeper configuration.