# Node 22+ ESM-only support and refined upload, proxy, and error handling

**Version:** v8.0.0

**Published:** August 12, 2026

`@sanity/client` v8 is the first step in modernizing the JavaScript client. For most users this will be an uneventful upgrade. The main exception is anyone still running end-of-life Node.js versions. Benefits include less maintenance overhead, fewer dependencies, and better stack traces.

## What changed

### Node 22.12+ required and ESM-only

Node 20 went out of LTS in April 2026 and is no longer supported. The minimum Node version is 22.12. The package now ships as ESM only. The CommonJS bundle, `./dist/*.cjs` files, and the CJS main entry are gone.

This is a soft change for most users: Node 22.12+ supports `require(esm)` natively, so existing code like `const {createClient} = require('@sanity/client')` continues to work without any changes. ESM import is still preferred. If you cannot move off an older Node version, stay on v7.

### Upload progress events

`HttpRequestEvent`, `ResponseEvent`, and `ProgressEvent` are removed. Observable asset uploads now use dedicated event types: `UploadEvent<T>`, `UploadResponseEvent<T>`, and `UploadProgressEvent`. The type discriminants (`'response'`/`'progress'`) and the progress event shape are unchanged.

Progress events now fire only in browsers. In Node and edge runtimes, observable uploads emit only the terminal response event. The Promise-based `client.assets.upload()` is unchanged.

### Proxy configuration

The `proxy` option can no longer be passed with individual requests. Configure proxy on the client config instead (Node.js only), or set `HTTP_PROXY`, `HTTPS_PROXY`, or `NO_PROXY` before the process starts. Proxy environment variables are read once at startup, not per-request.

### The `uri` option removed — use `url`

The legacy `uri` alias in `client.request()` is gone. Use `url` instead. This is a rename only; the value and behavior are unchanged.

### Error messages now include HTTP status text

`ClientError` and `ServerError` messages now read `'HTTP 400 Bad Request'` rather than `'HTTP 400'`. If you match error messages in tests, update your patterns. The structured fields on the error (`statusCode`, `responseBody`, etc.) are unchanged.

### UMD bundle removed

The UMD bundle is no longer included in the distribution. Use a bundler or a service like esm.sh instead.

### DNS errors retried

DNS `ENOTFOUND` errors are now retried for idempotent requests (`GET`, `HEAD`) with standard exponential backoff. Pass `maxRetries: 0` to fail immediately instead.

### Other removals

`unstable__adapter` and `unstable__environment` exports are removed. The `_requestHandler` client config option and `RequestHandler` type are removed. The `requester` client config option is removed. `typesVersions` declarations are removed. Use TypeScript `moduleResolution` set to `node16`, `nodenext`, or `bundler`.

## Migration guide

See the full migration guide [on GitHub](https://github.com/sanity-io/client/blob/main/docs/MIGRATE-v7.md) for step-by-step instructions on each breaking change.

