# up-fetch: a typed Fetch client builder for TypeScript

> up-fetch wraps the platform Fetch API with schema validation, automatic parsing, retries, timeouts, progress, streaming, and reusable defaults. It suits TypeScript applications that want shared client configuration while retaining familiar fetch semantics.

**L-Blondy/up-fetch** — Advanced fetch client builder

- Repository: https://github.com/L-Blondy/up-fetch
- Stars: 1,410 · Forks: 22
- Language: TypeScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/l-blondy-up-fetch

## Why up-fetch fits typed API clients

up-fetch addresses a specific problem in TypeScript applications: native fetch gives developers a consistent request interface, but it leaves each application to construct URLs, serialize bodies, parse response bodies, apply repeated request policies, and connect runtime validation with inferred result types. up-fetch keeps the native Fetch API available while adding those application concerns around it.

The intended audience is developers building API clients in TypeScript. The README specifically demonstrates response validation with Zod and Valibot, and the package description identifies up-fetch as an advanced fetch client builder. Its package metadata lists API access, schema validation, streaming, progress, retry, and fetch wrapping as its areas of concern.

A useful example is a user request whose response schema contains `id`, `name`, and `avatar`. Native fetch returns a `Response`, leaving response conversion separate from endpoint code. up-fetch accepts that schema through its `schema` option and the README states that the returned response is parsed and typed from it. This is more useful when several endpoints need the same treatment, especially if they share a base URL, timeout, headers, or authentication policy.

The boundary is equally important. up-fetch is not a server framework, mock server, cache, or replacement for application state management. It also does not make an undocumented remote API reliable by itself. Its documented value sits in the client layer around Fetch.

## How up-fetch configures requests and validates responses

An up-fetch instance begins with `up(fetch)`. The function receives the Fetch implementation directly, which keeps the familiar fetch calling convention instead of introducing a separate request builder object. The package metadata also exposes ES module and CommonJS entry points, and the repository includes TypeScript declarations through its `types` entry.

Reusable configuration is supplied through a defaults callback. The README shows `baseUrl` and `timeout` in that callback, while individual requests can supply `params`, `body`, `schema`, `retry`, and other request options. This gives the client a compact separation between defaults and endpoint-specific decisions. Lifecycle hooks can observe or mutate request options before the request, then handle successful or failed outcomes.

Request data follows two convenience paths. Query parameters can be supplied as a `params` object, and object bodies can be supplied as a `body` value without manually calling `JSON.stringify`. The README says that `serializeParams` and `serializeBody` can customize those transformations. Native fetch body types remain supported, so callers are not forced to use only the object shorthand.

Response validation follows the Standard Schema Specification. The documentation names Zod 3.24+ and Valibot 1.0+, and says that any library implementing the specification can be used. That compatibility comes from the schema contract rather than from a fixed Zod-specific integration. If a schema is supplied, the result is parsed before the request promise resolves.

Failure and timing policies sit in the same request path. A timeout can be set per request or in instance defaults. Retry configuration supports attempts, delay, and request-specific conditions. Error handling can be customized, and the README also describes an error-as-value mode. These mechanisms reduce repeated client code, although they remain explicit configuration rather than automatic recovery for every failed request.

## Installing up-fetch and making the first request

The README gives npm as the installation path. This installs the published package into an existing TypeScript project. The repository also lists `package-lock.json`, but it does not present that file as a separate application setup requirement.

```bash
npm i up-fetch
```

Create a reusable client in a module. Passing `fetch` to `up` follows the documented quick start and leaves the returned function available to the rest of the application.

```ts
import { up } from 'up-fetch'

export const upfetch = up(fetch)
```

A first endpoint can then use a Zod schema. The README lists Zod 3.24+ for this example, so a project should confirm that its installed Zod version satisfies that documented range.

```ts
import { upfetch } from './upfetch'
import { z } from 'zod'

const user = await upfetch('https://a.b.c/users/1', {
   schema: z.object({
      id: z.number(),
      name: z.string(),
      avatar: z.string().url(),
   }),
})
```

According to the README, `user` is already parsed and typed from the schema. The project extends native Fetch, so standard fetch options remain available. These commands and examples document installation and first use, not execution in a particular environment.

## Retries, timeouts, hooks, and per-client defaults

up-fetch is most useful when a service has a shared network policy. The documented defaults callback can set a base URL and timeout once, avoiding repetition across endpoint modules.

```ts
const upfetch = up(fetch, () => ({
   baseUrl: 'https://a.b.c',
   timeout: 30000,
}))
```

Hooks provide request lifecycle extension points. `onRequest` receives the options before the request and may mutate them. `onSuccess` receives parsed data and options, while `onError` receives the error and options. This is useful for authentication headers or request correlation, although the README does not prescribe a particular authentication implementation.

Retry behavior is configurable rather than unconditional. The documented configuration includes attempts and delay, and the examples show exponential delay and retry behavior based on the request method. A request can override the instance policy with its own `retry` object.

```ts
const upfetch = up(fetch, () => ({
   retry: {
      attempts: 3,
      delay: 1000,
   },
}))
```

The retry delay can also be a function. The example computes a delay from the attempt number, which makes retry behavior explicit and testable in application code.

Timeout values can be set per request with `timeout: 3000`, or established as defaults with `timeout: 5000`. These values are documented configuration examples. They do not specify the underlying timer implementation or the exact error produced on expiry, so those details need confirmation from the API reference or source before an application depends on them.

## Streaming, progress, and the native Fetch alternative

For endpoints that return incremental data, the README includes dedicated streaming and progress features. The topic list and package keywords also identify streaming and progress as project capabilities. The README does not show the complete streaming or progress API, so it would be inaccurate to invent callback names, return values, or progress event semantics. The repository's API reference and source are the appropriate places to verify those details.

The clearest alternative is native Fetch itself. Native Fetch does not require a wrapper, preserves direct access to `Request`, `Response`, headers, streams, and browser or runtime networking behavior, and avoids adding a client-builder dependency. It also leaves URL construction, body serialization, response parsing, retries, and validation to each caller.

up-fetch takes a different approach. It keeps the native fetch API as its base while adding shared defaults and higher-level conveniences. That tradeoff favors consistency across a TypeScript codebase, but it also adds an abstraction whose options and error semantics must be understood. A project with only a few one-off requests may find native Fetch simpler. A codebase with many validated API calls may prefer to standardize those rules in one client.

## up-fetch maintenance, packaging, and adoption limits

The repository is not archived, and its last push was on 2026-09-01. The recent release list includes `v2.6.1` on 2026-09-01, following `v2.6.0-beta.3` and `v2.6.0-beta.2` from 2026-03-09. The repository record indicates recent activity, but it does not by itself establish compatibility with every runtime or guarantee long-term support.

The package is published under the MIT license. The repository includes a `LICENSE` file, and `package.json` declares the same license identifier. That means the project is presented as permissively licensed, but application owners still need to review the license text and any dependency licenses separately. up-fetch lists no runtime dependencies, while Zod, Valibot, Vitest, MSW, and other packages appear as development dependencies in `package.json`.

A real limitation is that schema support depends on Standard Schema compatibility and on the selected schema library's documented version. Retry behavior also requires deliberate configuration. The library cannot determine which HTTP operations are safe to repeat, so callers should avoid treating a retry policy as permission to repeat every mutation.

There is another operational boundary: up-fetch builds on the Fetch implementation supplied to `up(fetch)`. The documentation does not claim to provide a server runtime, request cache, connection pool, or authentication service. Those concerns remain application or platform responsibilities.

## Conclusion

Adopt up-fetch for TypeScript services that repeatedly validate and parse API responses, or that need shared defaults, retries, timeouts, and request hooks. Do not adopt it merely to hide fetch behind a different request API, since it deliberately preserves native fetch options. Before integration, verify the runtime fetch implementation, schema library compatibility, retry conditions, and the behavior of streaming or progress handling in your target environment. The clearest adoption boundary is the `up(fetch)` client plus a `schema` for endpoints whose response contract matters.

## FAQ

### How do I install up-fetch?

The README documents `npm i up-fetch`. After installation, import `up` from `up-fetch` and create an instance with `up(fetch)`.

### Which schema libraries does up-fetch support?

up-fetch follows the Standard Schema Specification, so the documentation says it can work with libraries implementing that specification. The README specifically demonstrates Zod 3.24+ and Valibot 1.0+.

### Does up-fetch replace the native Fetch API?

No. The README says that up-fetch extends the native Fetch API and keeps standard fetch options available. It adds conveniences such as defaults, parsing, schema validation, retries, timeouts, hooks, streaming, and progress tracking.

## Sources

- [Issues](https://github.com/L-Blondy/up-fetch/issues)
- [L-Blondy/up-fetch on GitHub](https://github.com/L-Blondy/up-fetch)
- [License: MIT](https://github.com/L-Blondy/up-fetch/blob/master/LICENSE)
- [README](https://github.com/L-Blondy/up-fetch/blob/master/README.md)
- [Releases](https://github.com/L-Blondy/up-fetch/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/l-blondy-up-fetch
