better-fetch
A type-safe fetch wrapper for TypeScript with Standard Schema validation, pre-defined routes, retries, and a plugin system.
Repository Health
Technical Analysis
Better Fetch wraps the native fetch API with runtime validation, typed responses, and an error-as-value result shape ({ data, error }) instead of throwing by default. It validates requests and responses against any Standard Schema-compliant library (Zod, Valibot, ArkType, or others), so teams aren’t locked into one validator, and it infers TypeScript types directly from those schemas.
Beyond validation, it adds the pieces most fetch wrappers hand-roll separately: a createFetch factory for building configured client instances, createSchema for pre-defining routes with typed input/output/query/params/headers, linear and exponential retry strategies, request timeouts, and a plugin system with request/response/success/error/retry hooks. It runs anywhere fetch does — browsers, Node 18+, Deno, Bun, and edge/worker runtimes.
What You Get
- The
betterFetchfunction for one-off typed requests with generic or Standard Schema-inferred response types createFetchto build a reusable, pre-configured client with a sharedbaseURL, headers, retry policy, and pluginscreateSchemato pre-define routes (including dynamic:paramsegments and@methodmodifiers) with input/output/query/params/header validation- Built-in linear and exponential retry strategies with custom
shouldRetryconditions and request timeouts viaAbortController - A plugin system with
inithooks that can rewrite the URL/options before a request, plusonRequest/onResponse/onSuccess/onError/onRetrylifecycle hooks - An error-as-value response shape (
{ data, error }) by default, orthrow: trueto raise a typedBetterFetchErrorinstead
Common Use Cases
- Building a typed SDK/client for an internal or third-party HTTP API without hand-writing response types
- Sharing one configured fetch instance (base URL, auth headers, retry policy) across a frontend or backend codebase
- Documenting and validating an API’s routes centrally via
createSchema, catching request/response shape drift before it reaches the network - Adding resilience (timeouts, exponential backoff retries) to flaky third-party API calls without a bespoke retry loop
- Extending fetch behavior (auth injection, logging, request rewriting) through composable plugins instead of ad hoc wrapper functions
Under The Hood
Architecture
The library’s core betterFetch function (fetch.ts) is a single request pipeline: it resolves plugins and hooks via initializePlugins (plugins.ts), builds a stable request context object, runs onRequest hooks, issues the native fetch call with an AbortController-backed timeout, then walks a success or error branch that runs onResponse/onSuccess/onError hooks, optional Standard Schema validation, and an optional retry strategy (retry.ts) that recurses back into betterFetch on failure. createFetch (create-fetch/index.ts) layers a configured client on top by injecting an internal applySchemaPlugin, which resolves a pre-defined route from createSchema and merges its validated input/output/headers/params/query into the request options. The design cleanly separates request construction, plugin/hook orchestration, retry policy, and schema resolution into independent modules, so each concern (URL building in url.ts, header/body/timeout helpers in utils.ts) can be tested and swapped in isolation.
Tech Stack
The package is pure TypeScript with zero runtime dependencies, relying only on the platform’s native fetch/Response/AbortController and an internal StandardSchemaV1 interface that lets any Standard Schema-compliant validator (Zod, Valibot, ArkType) plug in without a hard dependency on any one of them. It builds with tsdown to dual ESM/CJS output (dist/index.js / dist/index.cjs), lints and formats with Biome, and is versioned/released through bumpp and a GitHub Actions release workflow inside a pnpm workspace monorepo alongside a companion logger package and a Fumadocs-based documentation site.
Code Quality
The package has an extensive Vitest test suite (five files, over 1,500 lines) covering the core fetch pipeline, createFetch/schema behavior, URL construction, and utility helpers, run through a vitest.workspace.ts across the monorepo. tsconfig.json enables strict mode plus exactOptionalPropertyTypes and noImplicitReturns for stronger type guarantees, and CI (ci.yml) runs build, typecheck, and test on every push and pull request. Source files carry extensive JSDoc comments on public option types, and errors are represented as a typed BetterFetchError class rather than swallowed or left as any.
What Makes It Unique
Rather than binding to one validation library, Better Fetch is built against the Standard Schema specification, so the same request/response validation code works with Zod, Valibot, ArkType, or any other compliant validator interchangeably. Its createSchema/fetch-schema feature goes further than typical fetch wrappers by letting teams pre-define an API’s entire route surface, including dynamic path parameters and HTTP-method modifiers, as a single typed map that documents and validates the API centrally, rather than scattering ad hoc types across call sites.
Used by 2 apps in this directory
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
supermemory
AI Development · Productivity · Note Taking
The state-of-the-art memory and context engine for AI agents — ranked #1 on all three major AI memory benchmarks.