This major version represents a significant evolution of the library.
After extensive development, v3 delivers a smaller, faster, and more powerful fetch wrapper with improved type safety, smarter defaults, and exciting new features.
✨ What's New
🚀 Embracing Modern JavaScript
Wretch v3 now requires Node.js 22 or higher, allowing us to fully embrace the native Web APIs that are now built into the runtime. This means zero polyfill overhead - fetch
, FormData
, URLSearchParams
, AbortController
, and the Performance API are all used directly from Node.js.
The result? A significantly smaller bundle size and better performance thanks to highly optimized native implementations.
🎯 Better Error Handling with .customError()
Say goodbye to .errorType()
and hello to the new .customError()
method! This new helper function provides full TypeScript support for custom error properties, giving you complete control over error parsing.
Instead of being limited to predefined error types, you can now transform and parse errors exactly how you need them:
interface ApiError {
code: number
message: string
details?: string
}
const api = wretch("https://api.example.com")
.customError<ApiError>(async (error, response) => {
return { ...error, json: await response.json() }
})
api.get("/users")
.badRequest(error => {
console.log(error.json.message) // Fully typed!
})
.json()
🔄 Smarter Retry Defaults
The retry middleware now skips retrying 4xx client errors and focuses only on 5xx server errors and network failures.
This aligns perfectly with HTTP semantics - client errors like bad requests or authentication issues typically won't be fixed by retrying, while server errors and network issues are often transient:
import { retry } from "wretch/middlewares"
// Only retries 5xx and network errors, skips 4xx
wretch()
.middlewares([retry()])
.get("/api/data")
.json()
Of course, you can still customize this behavior if needed using the until
option.
📤 Upload Progress Monitoring
The Progress addon now lets you track upload progress in real-time:
import ProgressAddon from "wretch/addons/progress"
import FormDataAddon from "wretch/addons/formData"
await wretch("https://api.example.com/upload")
.addon([ProgressAddon(), FormDataAddon])
.formData({ file: myFile })
.onUpload((loaded, total) => {
console.log(`Upload: ${(loaded / total * 100).toFixed(0)}%`)
})
.post()
.json()
This works seamlessly in Node.js for both HTTP and HTTPS. Note that browser support varies - Chrome/Chromium requires HTTPS, and Firefox doesn't support request body streaming yet.
🎨 Multiple Addons at Once
Small quality-of-life improvement, you can now pass multiple addons in a single call making your setup cleaner:
import QueryStringAddon from "wretch/addons/queryString"
import FormDataAddon from "wretch/addons/formData"
import AbortAddon from "wretch/addons/abort"
const api = wretch("https://api.example.com")
.addon([QueryStringAddon, FormDataAddon, AbortAddon()])
💎 Improved API Design
Several addon methods now use options objects instead of positional parameters. This makes the API more maintainable, easier to extend in the future, and more readable:
// Query strings with clear options
wretch("https://api.example.com")
.addon(QueryStringAddon)
.query({ search: "test" }, { replace: true })
.query({ filter: undefined }, { omitUndefinedOrNullValues: true })
// FormData with recursive options
wretch("https://api.example.com")
.addon(FormDataAddon)
.formData(data, { recursive: true })
🔗 Converting to Native Fetch
Need to pass a Wretch request to code that expects a native fetch call? The new .toFetch()
method converts a Wretch request chain into a standard fetch invocation:
const [url, options] = wretch("https://api.example.com")
.headers({ "X-Custom": "header" })
.toFetch()
// Now use with native fetch or other libraries
await fetch(url, options)
🧹 Simplified Architecture
Version 3 removes global configuration methods in favor of cleaner per-instance configuration. Methods like wretch.options()
, wretch.errorType()
, and wretch.polyfills()
are gone - now you configure each instance explicitly.
// ❌ v2 - Global configuration (removed in v3)
import wretch from 'wretch'
wretch.options({ mode: 'cors' })
wretch.errorType('json')
const api1 = wretch('https://api1.example.com')
const api2 = wretch('https://api2.example.com')
// ✅ v3 - Share configuration through a base wretch instance
import wretch from 'wretch'
const baseApi = wretch()
.options({ mode: 'cors' })
.customError(async (error, response) => {
return { ...error, json: await response.json() }
})
const api1 = baseApi.url('https://api1.example.com')
const api2 = baseApi.url('https://api2.example.com')
const api3 = baseApi.url('https://api3.example.com')
🔧 Modernized Development Stack
Behind the scenes, Wretch v3 represents a complete modernization of the development infrastructure:
Rolldown for bundling - Migrated from Rollup to Rolldown, resulting in significantly faster build times and a more efficient development workflow.
Native Node.js testing - Replaced Jest with Node.js's built-in node:test
runner. No more heavy test framework dependencies - just fast, native testing that works out of the box.
Documentation testing - All code snippets in the documentation are now automatically tested to ensure they actually work. No more outdated examples!
Security updates - Resolved all security vulnerabilities and upgraded all development dependencies to their latest versions. The project is now running on modern, secure tooling throughout.
Comprehensive cross-runtime testing - Test suite now runs across Node.js, Deno, Bun, and browsers (via Web Test Runner) to ensure Wretch works flawlessly everywhere.
Automated publishing - Added automated npm publishing workflow for smoother releases.
These internal improvements mean faster development, more reliable releases, and better confidence that everything works as documented.
📖 Migration Guide
Wretch v3 includes breaking changes, but they're all for good reasons! Here are the key changes you'll need to handle:
Node.js version: You'll need Node.js 22 or higher to use v3. If you need to support older versions, stick with Wretch v2.
Error handling: Replace .errorType()
with .customError()
for more flexible, type-safe error parsing.
Global configuration: Remove calls to static methods like wretch.options()
and configure each instance instead.
Addon parameters: Some addon methods now use options objects - notably .query()
, .formData()
, and .setTimeout()
.
For complete migration instructions with examples for every breaking change, check out the detailed migration guide.
📦 Installation
Ready to upgrade?
npm install wretch@latest
Need to stay on Node.js < 22?
npm install wretch@^2
💝 Thank You
Special thanks to all the users who have provided feedback and feature requests over the years. Your input helped shape this release and make Wretch better for everyone!
Happy wretching! 🎊